Libraries

library(dplyr)
library(tidyverse)
library(stringr)
library(ggplot2)

Summary

With the purpose of finding how much the 4P’s of marketing affect game ownership on Steam and its importance, 3 main questions were analyzed. The three questions are as follows: what does the Steam market look like, will the genre affect game ownership, and whether price expectations differ between genres.

The data set sourced from Kaggle was first cleaned using the Dplyr and Tidyverse packages. Then, moving to the analysis, knowing that Steam is a site for distributing games rather than a variety of selected games, it was decided that of the 4P’s, place should be the first aspect considered. With the majority of games having very few players compared to the most popular games, the data showed a negative exponential distribution, meaning that to gain notoriety on steam, games need to be marketed which begins with the product. With this information the next step was to narrow the data and look into the top 250 games and then find the genre that appeared the most in that subset, the action genre. Afterwards the focus was shifted to look at steam from a developer looking to distribute a Simulation game.

Having analyzed the results, it was found that game ownership is indeed a good metric for a successful game due to how many aspects show strong correlations to the estimated ownership of the game. With this in mind, analysis shows that simulation games tend to garner less players than the action genre Additionally, games in the Simulation genre are typically priced higher than the most popular games showing that such games typically are more complex than games only in the action genre. Knowing this, the data shows that the genre, or product in marketing terms, changes the price and how well the game may be received on Steam.

Purpose

Steam is one of the largest online marketplaces for PC games offering over 100,000 games on the platform. Steam game catalogue is massive, meaning that the ownership of a game is not necessarily indicative of its quality or enjoyment, more so, the game has been buried. The purpose of this project is to see how games perform on steam by analyzing the platform itself, looking to see if the product (genre) affects ownership, then seeing if price expectations change between genres. What follows is an organized approach to the analysis:

  1. What does Steam look like as a Market place
  2. How much does the product/genre matter concerning game ownership?
  3. Are there different price expectations between Genres?

Using this data the hope is to create a presentation, find inspiration, and most importantly, present the data in a way that is readable and understandable. With the help of R Studio, the goal is to evaluate whether understanding the 4Ps of marketing can help developers increase ownership of their game on Steam. To do this, Steam’s marketplace will be analyzed from the perspective of a developer looking to post a Simulation game, by analyzing the top genres and popular games, and discovering how much place, product, and price matter on the platform.

Data

Dictionary

Variable Name What the Variable Represents Numerical or Categorical?
AppID App ID is a unique ID that enables Steam to Differentiate one game from another despite its name Numerical
Name The name of the game Categorical
Estimated.owners The estimated number of people who own the game. Gives a range Categorical
Release.date The date the game released Categorical
Price The base price of the game Categorical
Supported.languages Details the languages that are supported by the game Categorical
User.score Steam’s way of summarizing player recommendations. It is a Percentage calculated by finding the number of positive reviews then dividing by total reviews Numerical
Positive Number of positive reviews Numerical
Negative Number of negative reviews Numerical
Achievements Number of achievements available in the game Numerical
Recommendations Number of recommendations Numerical
Average.playtime.two weeks Average play time over two week measured in hours Numerical
Average.playtime.forever Average total playtime Numerical
Median.playtime.two.weeks Median playtime over two weeks (less susceptible to outliers) Numerical
Median.playtime.forever Median total playtime Numerical
Developers The developers of the game Categorical
Publishers The publishers of the game Categorical
Categories Denotes what kind of game it is (online, single-player, ect.) Categorical
Genres Denotes the multiple genres of the game Categorical
Tags More specific than ‘Genres’ (clicker, agriculture, sandbox) Categorical

Missing/NA/Null Variables

The Data was scraped from Steam meaning there are many values that have odd formatting. Originally, it was believed this was an issue with how the data was gathered and that those values were This being said, after some research it was found that the symbols in the “Name” column was a form of Unicode and the text is perfectly decipherable. This occurs as a result of using characters from different languages. Changing those values into Unicode is the computer’s way of representing characters from almost all of the world written languages. In essence, the Unicode present in the data is not a result of bad scraping. This being said, a few NA values were found, but these values have little affect on the calculations and have posed little problems outside of the user score correlation analysis. This column showed some major NA values; however, this would only be a problem if it was decided to look outside of the project scope.

Methodology for Cleaning the data

The data is rather tidy with the exception of the Genres Column. The Genres column contains a list of tagged genres rather than a single value. I decided to leave the Genres column alone because much of the analysis will rely on that single column. If the values were to be separated, the amount of columns per row would be different due to Steam’s allowance of multiple genre tags. In consideration of needing to keep the data together, the grepl() function will be a big help the focus is narrowed to specific genres within the column. The function allows R to find specific strings within columns rather than splitting the genres column as will be done to find the most common genres on Steam.

Though the data is very consistent, there are a few difficulties in places where text is formatted, particularly when it comes to games with special characters or formatting not available on the typical English keyboard. This is only a minor convenience because the text can still be decoded. Additionally, there are a few columns that could be better utilized if they were numerical values. The main offender is the estimated owner’s column. To fix this issue, the values will be separated into min and max then the average of both will be mutated into a new column which most of the analysis will be completed with.

#4a. Read in data

OG_Steam <- read.csv("Steam_Games.csv", fill = TRUE)

OG_Steam
ABCDEFGHIJ0123456789
AppID
<int>
20200
655370
1732930
1355720
1139950
1469160
1659180
1968760
1178150
320150
NA
#4b.1 show a summary of the data and the first few observations

#Summary
summary(OG_Steam)
     AppID             Name           Release.date       Estimated.owners      Peak.CCU          Required.age         Price         
 Min.   :     10   Length:109780      Length:109780      Length:109780      Min.   :      0.0   Min.   : 0.0000   Min.   :   0.000  
 1st Qu.: 925058   Class :character   Class :character   Class :character   1st Qu.:      0.0   1st Qu.: 0.0000   1st Qu.:   0.990  
 Median :1642805   Mode  :character   Mode  :character   Mode  :character   Median :      0.0   Median : 0.0000   Median :   3.990  
 Mean   :1705773                                                            Mean   :    178.7   Mean   : 0.2569   Mean   :   7.041  
 3rd Qu.:2430293                                                            3rd Qu.:      1.0   3rd Qu.: 0.0000   3rd Qu.:   9.990  
 Max.   :3671840                                                            Max.   :1311366.0   Max.   :21.0000   Max.   : 999.980  
                                                                                                                                    
 About.the.game     Supported.languages Full.audio.languages   Reviews          Header.image         Website         
 Length:109780      Length:109780       Length:109780        Length:109780      Length:109780      Length:109780     
 Class :character   Class :character    Class :character     Class :character   Class :character   Class :character  
 Mode  :character   Mode  :character    Mode  :character     Mode  :character   Mode  :character   Mode  :character  
                                                                                                                     
                                                                                                                     
                                                                                                                     
                                                                                                                     
 Support.url        Support.email       Windows           Mac            Linux         Metacritic.score Metacritic.url    
 Length:109780      Length:109780      Mode :logical   Mode :logical   Mode :logical   Min.   : 0.000   Length:109780     
 Class :character   Class :character   FALSE:33        FALSE:90621     FALSE:96265     1st Qu.: 0.000   Class :character  
 Mode  :character   Mode  :character   TRUE :109747    TRUE :19159     TRUE :13515     Median : 0.000   Mode  :character  
                                                                                       Mean   : 2.658                     
                                                                                       3rd Qu.: 0.000                     
                                                                                       Max.   :97.000                     
                                                                                                                          
   User.score           Positive            Negative          Score.rank      Achievements     Recommendations    
 Min.   :  0.00000   Min.   :      0.0   Min.   :     0.0   Min.   : 97.00   Min.   :   0.00   Min.   :      0.0  
 1st Qu.:  0.00000   1st Qu.:      0.0   1st Qu.:     0.0   1st Qu.: 98.00   1st Qu.:   0.00   1st Qu.:      0.0  
 Median :  0.00000   Median :      4.0   Median :     1.0   Median : 99.00   Median :   0.00   Median :      0.0  
 Mean   :  0.03087   Mean   :    764.9   Mean   :   127.2   Mean   : 98.91   Mean   :  17.64   Mean   :    624.5  
 3rd Qu.:  0.00000   3rd Qu.:     29.0   3rd Qu.:     8.0   3rd Qu.:100.00   3rd Qu.:  17.00   3rd Qu.:      0.0  
 Max.   :100.00000   Max.   :5764420.0   Max.   :895978.0   Max.   :100.00   Max.   :9821.00   Max.   :3441592.0  
                                                            NA's   :109736                                        
    Notes           Average.playtime.forever Average.playtime.two.weeks Median.playtime.forever Median.playtime.two.weeks
 Length:109780      Min.   :     0.00        Min.   :    0.000          Min.   :     0.00       Min.   :    0.000        
 Class :character   1st Qu.:     0.00        1st Qu.:    0.000          1st Qu.:     0.00       1st Qu.:    0.000        
 Mode  :character   Median :     0.00        Median :    0.000          Median :     0.00       Median :    0.000        
                    Mean   :    82.29        Mean   :    9.213          Mean   :    73.59       Mean   :    9.909        
                    3rd Qu.:     0.00        3rd Qu.:    0.000          3rd Qu.:     0.00       3rd Qu.:    0.000        
                    Max.   :145727.00        Max.   :19159.000          Max.   :208473.00       Max.   :19159.000        
                                                                                                                         
  Developers         Publishers         Categories           Genres              Tags          
 Length:109780      Length:109780      Length:109780      Length:109780      Length:109780     
 Class :character   Class :character   Class :character   Class :character   Class :character  
 Mode  :character   Mode  :character   Mode  :character   Mode  :character   Mode  :character  
                                                                                               
                                                                                               
                                                                                               
                                                                                               
# This needed to be shown in a new window
head(OG_Steam)
ABCDEFGHIJ0123456789
 
 
AppID
<int>
Name
<chr>
Release.date
<chr>
Estimated.owners
<chr>
Peak.CCU
<int>
Required.age
<int>
Price
<dbl>
120200Galactic Bowling21-Oct-080 - 200000019.99
2655370Train Bandit12-Oct-170 - 20000000.99
31732930Jolt Project17-Nov-210 - 20000004.99
41355720Henosisâ„¢23-Jul-200 - 20000005.99
51139950Two Weeks in Painland3-Feb-200 - 20000000.00
61469160Wartune Reborn26-Feb-2150000 - 1000006800.00
#4b.2 First few observations
head(OG_Steam)
ABCDEFGHIJ0123456789
 
 
AppID
<int>
Name
<chr>
Release.date
<chr>
Estimated.owners
<chr>
Peak.CCU
<int>
Required.age
<int>
Price
<dbl>
120200Galactic Bowling21-Oct-080 - 200000019.99
2655370Train Bandit12-Oct-170 - 20000000.99
31732930Jolt Project17-Nov-210 - 20000004.99
41355720Henosisâ„¢23-Jul-200 - 20000005.99
51139950Two Weeks in Painland3-Feb-200 - 20000000.00
61469160Wartune Reborn26-Feb-2150000 - 1000006800.00
NA
#4c. Create a new data set from the variables that are of interest

Steam_Games_Pre <- OG_Steam %>%
  select(AppID, Name, Release.date, Estimated.owners, Price, Supported.languages, User.score, Positive, Negative, Achievements, Recommendations, Average.playtime.two.weeks, Average.playtime.forever, Median.playtime.two.weeks, Median.playtime.forever, Developers, Publishers, Categories, Genres, Tags)

#Example of how this dataset may be used

Publisher_Price_Summary <- Steam_Games_Pre%>%
  group_by(Publishers) %>%
  summarise(Avg_Price = mean(Price)) %>%
  arrange(-Avg_Price)
Publisher_Price_Summary
ABCDEFGHIJ0123456789
Publishers
<chr>
Avg_Price
<dbl>
A&S Inc.999.98000
Fury Games999.00000
Whoes heart broken500.00000
SideFX269.99000
3Dflow SRL199.99000
AT_Games199.99000
AssetFlipGames World Game Publishing,ALFINA WORLD GAME PUBLISHING,rocketship199.99000
BestEntrepeneurs199.99000
CatCat Gaming199.99000
Colyu199.99000

summary(Steam_Games_Pre)
     AppID             Name           Release.date       Estimated.owners       Price          Supported.languages
 Min.   :     10   Length:109780      Length:109780      Length:109780      Min.   :   0.000   Length:109780      
 1st Qu.: 925058   Class :character   Class :character   Class :character   1st Qu.:   0.990   Class :character   
 Median :1642805   Mode  :character   Mode  :character   Mode  :character   Median :   3.990   Mode  :character   
 Mean   :1705773                                                            Mean   :   7.041                      
 3rd Qu.:2430293                                                            3rd Qu.:   9.990                      
 Max.   :3671840                                                            Max.   : 999.980                      
   User.score           Positive            Negative         Achievements     Recommendations     Average.playtime.two.weeks
 Min.   :  0.00000   Min.   :      0.0   Min.   :     0.0   Min.   :   0.00   Min.   :      0.0   Min.   :    0.000         
 1st Qu.:  0.00000   1st Qu.:      0.0   1st Qu.:     0.0   1st Qu.:   0.00   1st Qu.:      0.0   1st Qu.:    0.000         
 Median :  0.00000   Median :      4.0   Median :     1.0   Median :   0.00   Median :      0.0   Median :    0.000         
 Mean   :  0.03087   Mean   :    764.9   Mean   :   127.2   Mean   :  17.64   Mean   :    624.5   Mean   :    9.213         
 3rd Qu.:  0.00000   3rd Qu.:     29.0   3rd Qu.:     8.0   3rd Qu.:  17.00   3rd Qu.:      0.0   3rd Qu.:    0.000         
 Max.   :100.00000   Max.   :5764420.0   Max.   :895978.0   Max.   :9821.00   Max.   :3441592.0   Max.   :19159.000         
 Average.playtime.forever Median.playtime.two.weeks Median.playtime.forever  Developers         Publishers         Categories       
 Min.   :     0.00        Min.   :    0.000         Min.   :     0.00       Length:109780      Length:109780      Length:109780     
 1st Qu.:     0.00        1st Qu.:    0.000         1st Qu.:     0.00       Class :character   Class :character   Class :character  
 Median :     0.00        Median :    0.000         Median :     0.00       Mode  :character   Mode  :character   Mode  :character  
 Mean   :    82.29        Mean   :    9.909         Mean   :    73.59                                                               
 3rd Qu.:     0.00        3rd Qu.:    0.000         3rd Qu.:     0.00                                                               
 Max.   :145727.00        Max.   :19159.000         Max.   :208473.00                                                               
    Genres              Tags          
 Length:109780      Length:109780     
 Class :character   Class :character  
 Mode  :character   Mode  :character  
                                      
                                      
                                      
#4d. Name the new dataset and write it to a csv file

write.csv(Steam_Games_Pre, "Steam_Games_Cleaned.csv")

Data Pre-processing

# Read in Data
Steam_Games <- read.csv("Steam_Games_Cleaned.csv")

Steam_Games
ABCDEFGHIJ0123456789
X
<int>
AppID
<int>
120200
2655370
31732930
41355720
51139950
61469160
71659180
81968760
91178150
10320150
# Get rid of 'X' column from Steam_Games_Cleaned

Steam_Games$X <- NULL
# Find the column names
colnames(Steam_Games)
 [1] "AppID"                      "Name"                       "Release.date"               "Estimated.owners"          
 [5] "Price"                      "Supported.languages"        "User.score"                 "Positive"                  
 [9] "Negative"                   "Achievements"               "Recommendations"            "Average.playtime.two.weeks"
[13] "Average.playtime.forever"   "Median.playtime.two.weeks"  "Median.playtime.forever"    "Developers"                
[17] "Publishers"                 "Categories"                 "Genres"                     "Tags"                      

Summary Statistics

# Summary Statistics

summary(Steam_Games_Pre)
     AppID             Name           Release.date       Estimated.owners       Price          Supported.languages
 Min.   :     10   Length:109780      Length:109780      Length:109780      Min.   :   0.000   Length:109780      
 1st Qu.: 925058   Class :character   Class :character   Class :character   1st Qu.:   0.990   Class :character   
 Median :1642805   Mode  :character   Mode  :character   Mode  :character   Median :   3.990   Mode  :character   
 Mean   :1705773                                                            Mean   :   7.041                      
 3rd Qu.:2430293                                                            3rd Qu.:   9.990                      
 Max.   :3671840                                                            Max.   : 999.980                      
   User.score           Positive            Negative         Achievements     Recommendations     Average.playtime.two.weeks
 Min.   :  0.00000   Min.   :      0.0   Min.   :     0.0   Min.   :   0.00   Min.   :      0.0   Min.   :    0.000         
 1st Qu.:  0.00000   1st Qu.:      0.0   1st Qu.:     0.0   1st Qu.:   0.00   1st Qu.:      0.0   1st Qu.:    0.000         
 Median :  0.00000   Median :      4.0   Median :     1.0   Median :   0.00   Median :      0.0   Median :    0.000         
 Mean   :  0.03087   Mean   :    764.9   Mean   :   127.2   Mean   :  17.64   Mean   :    624.5   Mean   :    9.213         
 3rd Qu.:  0.00000   3rd Qu.:     29.0   3rd Qu.:     8.0   3rd Qu.:  17.00   3rd Qu.:      0.0   3rd Qu.:    0.000         
 Max.   :100.00000   Max.   :5764420.0   Max.   :895978.0   Max.   :9821.00   Max.   :3441592.0   Max.   :19159.000         
 Average.playtime.forever Median.playtime.two.weeks Median.playtime.forever  Developers         Publishers         Categories       
 Min.   :     0.00        Min.   :    0.000         Min.   :     0.00       Length:109780      Length:109780      Length:109780     
 1st Qu.:     0.00        1st Qu.:    0.000         1st Qu.:     0.00       Class :character   Class :character   Class :character  
 Median :     0.00        Median :    0.000         Median :     0.00       Mode  :character   Mode  :character   Mode  :character  
 Mean   :    82.29        Mean   :    9.909         Mean   :    73.59                                                               
 3rd Qu.:     0.00        3rd Qu.:    0.000         3rd Qu.:     0.00                                                               
 Max.   :145727.00        Max.   :19159.000         Max.   :208473.00                                                               
    Genres              Tags          
 Length:109780      Length:109780     
 Class :character   Class :character  
 Mode  :character   Mode  :character  
                                      
                                      
                                      

Currently the estimated owners column is in a character format meaning it will need to be converted to a numerical datatype.

Data Dimensions

# Use dim (outcome is 109780 rows and 20 columns)

dim(Steam_Games)
[1] 109780     20

There are 109780 rows in this data set and 20 columns.

Data Exploration

Bar Graph: Player Count


# Update data set so min and max estimated players have their own columns

Steam_Games <- Steam_Games %>%
  separate(
    col = Estimated.owners,
    into = c('Min.estimated.owners', 'Max.estimated.owners'),
    sep = "-",
  )
  
#Convert Columns to numerical value

Steam_Games$Max.estimated.owners <- as.numeric(Steam_Games$Max.estimated.owners)

Steam_Games$Min.estimated.owners <- as.numeric(Steam_Games$Min.estimated.owners)
#Convert back to average estimated owners (most likely value)

Steam_Games <- Steam_Games %>%
  mutate(Owners.avg = (Min.estimated.owners + Max.estimated.owners) / 2)

head(Steam_Games$Owners.avg, 15)
 [1] 10000 10000 10000 10000 10000 75000 10000 10000 10000 75000 35000 75000 10000 35000 10000
ggplot(data = Steam_Games, aes(x = Owners.avg)) +
  geom_bar(fill = "cadetblue3", color = "cadetblue") + 
   labs(
    title = "Number of Games by Log of Estimated Owners",
    y = "Number of Games",
    x = "Estimated Owners"
   ) +
   scale_x_log10()

Graph Description:

The graph shows that an overwhelmingly large amount of games on steam have a small player base. This confirms that a player base of around 1000 players is considered to be about average for smaller game studios on steam regardless of genre.

Top 8 Most Common Genres on Steam

# Splitting the values from the 'Genres' column
Genres <- data.frame(
  Genres = Steam_Games$Genres
)

Genres_Split <- Genres %>%
  separate_longer_delim(Genres, delim = ",")

Genres_Split
ABCDEFGHIJ0123456789
Genres
<chr>
Casual
Indie
Sports
Action
Indie
Action
Adventure
Indie
Strategy
Adventure
NA
# Find the count for each Genre

    Genres_Count <- Genres_Split %>%
      count(Genres, sort = TRUE)

# Find top 8 genre

    Top_8_Genres <- Genres_Count %>%
      slice_head(n = 8)
    
# Print top 8
    
print(Top_8_Genres)
ABCDEFGHIJ0123456789
Genres
<chr>
n
<int>
Indie72080
Casual44412
Action42037
Adventure40166
Simulation21109
Strategy19947
RPG18796
Early Access13704
Top_8_Vec <- c("Indie", "Casual", "Action", "Adventure", "Simulation", "Strategy", "RPG", "Early Access")

Genres_Filter <- Genres_Split %>%
  filter(Genres_Split == Top_8_Vec)

print(Genres_Filter)
ABCDEFGHIJ0123456789
Genres
<chr>
Strategy
Casual
Casual
Indie
Simulation
Indie
Casual
Simulation
Strategy
Indie
# Summarize genre counts and calculate percentages
Genres_Filter <- Genres_Filter %>%
  count(Genres) %>%
  mutate(Percentage = round((n / sum(n)) * 100, 1))

# Pie chart with percentage labels
ggplot(Genres_Filter, aes(x = "", y = n, fill = Genres)) +
  geom_bar(stat = "identity", color = "white") +
  coord_polar(theta = "y") +
  geom_text(aes(label = paste0(Percentage, "%")),
            position = position_stack(vjust = 0.5),
            color = "white", size = 3.5) +
  labs(
    title = "Most Common Genres on Steam (Pie Chart)",
    x = NULL,
    y = NULL,
    fill = "Genre"
  ) +
  theme_void() +
  theme(
    plot.title = element_text(hjust = 0.5, face = "bold"),
    legend.position = "right"
  ) +
  scale_fill_manual(values = c("cadetblue2","cadetblue3", "cadetblue","cadetblue4","mediumseagreen", "seagreen","green4","darkgreen"))

Graph Description:

The above graph shows how many games on steam are categorized under different genres. This graph in particular only shows the top 8 genres due to how many games use these genre tags specifically. The indie genre is the most popular tag. This shows that most games on Steam are made by independent developers. Additionally, it seems that many games use the casual tag.

Finding my Preferred Games

The ‘Preferred_Games’ vector contains games that I find to be enagaging and enjoyable. With the goal of finding which genre I lean towards the most. Every genre is different, Choosing a genre I know the most about will help me identify key aspects that make those games stand out among

# Preferred Games 
# Check Names (Not checked)

Preferred_Games <- c("Cinnabunny", "Potion Craft: Alchemist Simulator", "Stardew Valley", "Cities: Skylines", "Good Pizza, Great Pizza - Cooking Simulator Game", "Papa's Freezeria Deluxe", "Sticky Business", "Slime Rancher 2", "Albion Online", "Squirreled Away")

#grab games

Favorite_Games <- Steam_Games %>%
  filter(Name %in% Preferred_Games)

#print favorite games
Favorite_Games
ABCDEFGHIJ0123456789
AppID
<int>
Name
<chr>
Release.date
<chr>
Min.estimated.owners
<dbl>
255710Cities: Skylines10-Mar-155e+06
761890Albion Online16-May-182e+06
770810Good Pizza, Great Pizza - Cooking Simulator Game5-Jun-185e+04
1210320Potion Craft: Alchemist Simulator21-Sep-215e+05
413150Stardew Valley26-Feb-161e+07
1657630Slime Rancher 222-Sep-222e+05
2291760Papa's Freezeria Deluxe31-Mar-232e+04
2303350Sticky Business17-Jul-232e+04
2794830Cinnabunny19-Feb-250e+00
2977620Squirreled Away28-Mar-250e+00

Correlation Analysis on top 250 games

# Find the top 250 games in the Steam library

Top_250_Games <- Steam_Games %>%
  arrange(desc(Owners.avg)) %>%
  
  head(250)

correlation_matrix_250 <- Top_250_Games %>%
  select(
    Owners.avg, Price, Positive, Negative, 
         Achievements, Recommendations, 
         Average.playtime.two.weeks, Average.playtime.forever) %>%
  mutate(across(everything(), as.numeric)) %>%  # converts all columns to the numeric datatype
  cor(use = "pairwise.complete.obs")            # handles missing values

correlation_matrix_250
                           Owners.avg       Price    Positive    Negative Achievements Recommendations Average.playtime.two.weeks
Owners.avg                  1.0000000 -0.10669394  0.60153627  0.59286065   0.10950162      0.47075473                 0.23329474
Price                      -0.1066939  1.00000000 -0.02363854 -0.05373682   0.09503967      0.06664440                -0.03616313
Positive                    0.6015363 -0.02363854  1.00000000  0.75897948   0.11084977      0.91596727                 0.10686957
Negative                    0.5928606 -0.05373682  0.75897948  1.00000000   0.04239992      0.79744867                 0.13494968
Achievements                0.1095016  0.09503967  0.11084977  0.04239992   1.00000000      0.08891216                 0.05274189
Recommendations             0.4707547  0.06664440  0.91596727  0.79744867   0.08891216      1.00000000                 0.06745812
Average.playtime.two.weeks  0.2332947 -0.03616313  0.10686957  0.13494968   0.05274189      0.06745812                 1.00000000
Average.playtime.forever    0.6193225  0.04583561  0.62775208  0.63432460   0.16631237      0.55232036                 0.22612711
                           Average.playtime.forever
Owners.avg                               0.61932248
Price                                    0.04583561
Positive                                 0.62775208
Negative                                 0.63432460
Achievements                             0.16631237
Recommendations                          0.55232036
Average.playtime.two.weeks               0.22612711
Average.playtime.forever                 1.00000000
Key Correlations and Thoughts

Based on this correlation matrix, I would like to focus on 3 different aspects for further analysis; Owners.avg, player engagement of all kinds (Positive, Negative, and Recommendations), and Price. Owners.avg has the biggest impact on every aspect of the game while player engagement seems to drive how many copies of the game are sold. Though the price column does not seem to have any strong correlations, it is the aspect with the most slightly negative relationships in most aspects while increasing forever playtime.

Comparison Data Visualisations

Top_250 for Comparison

For my next series of analysis I chose to focus on the Top 250 games of each genre and popularity. Because Steam is such a large platform the most common aspect of a genre is not neccesarily the most successful as shown by the player count bar graph.

#Now do the same steps from finding the Top_250_Games to find the 250 most popular games within the simulation genre

#Make a subset:

#Subset of simulation games
Sim_Games <- Steam_Games[grepl("Simulation", Steam_Games$Genres), ]


#Find the top 250 from sim games 

Top_250_Sims <- Sim_Games %>%
  arrange(desc(Owners.avg)) %>%
  
  head(250)

Top_250_Sims
ABCDEFGHIJ0123456789
 
 
AppID
<int>
Name
<chr>
Release.date
<chr>
14000Garry's Mod29-Nov-06
2236390War Thunder15-Aug-13
31468810鬼谷八è\u008d’ Tale of Immortal27-Jan-21
4242760The Forest30-Apr-18
5261550Mount & Blade II: Bannerlord30-Mar-20
6552990World of Warships15-Nov-17
7417910Street Warriors Online16-Dec-16
8291480Warface1-Jul-14
9301520Robocraft24-Aug-17
10477160Human: Fall Flat22-Jul-16
Top_250_Games
ABCDEFGHIJ0123456789
 
 
AppID
<int>
Name
<chr>
Release.date
<chr>
Min.estimated.owners
<dbl>
1570Dota 29-Jul-131e+08
21063730New World28-Sep-215e+07
3578080PUBG: BATTLEGROUNDS21-Dec-175e+07
4440Team Fortress 210-Oct-075e+07
5730Counter-Strike: Global Offensive21-Aug-125e+07
62358720Black Myth: Wukong19-Aug-245e+07
71172470Apex Legendsâ„¢4-Nov-202e+07
84000Garry's Mod29-Nov-062e+07
91085660Destiny 21-Oct-192e+07
10359550Tom Clancy's Rainbow Six® Siege1-Dec-152e+07

Playership

Grouped Bar chart to compare player bases

# Now that we have our broad sets, Create a grouped bar chart to compare player bases

# Select Columns Sets to include max owners and Name
Top_250_Games_MO <- Top_250_Games %>%
  select(Owners.avg, Name)
Top_250_Sims_MO <- Top_250_Sims %>%
  select(Owners.avg, Name)

# Convert data to be in the same set
Top_250_Games_MO$Source <- "General"
Top_250_Sims_MO$Source <- "Simulations"

Top_Compare_250 <- rbind(Top_250_Games_MO, Top_250_Sims_MO) #rbind takes the two columns and makes the two one

# Summarize the data to get the counts
summary_data <- Top_Compare_250 %>%
  group_by(Source) %>%
  summarise(Count = n()) # n() counts the number of rows in each group

# Create Bins
Top_Compare_250$Owner_Bins <- cut(Top_Compare_250$Owners.avg, breaks = 20)

# 2. Plot the data using the new bins
ggplot(Top_Compare_250, aes(x = Owner_Bins, fill = Source)) +
  geom_bar(position = "dodge", color = "cadetblue4") +
  labs(
    title = "Simulation and Top 250 Games Comparison by Estimated Owners",
    x = "Estimated Owners",
    y = "Count of Games",
    fill = "Data Source"
  ) +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 90, hjust = 1, vjust = 0.5)) +

  scale_fill_manual(values = c("cadetblue3", "darkgrey"))

Graph Description:

The above graph shows that, when compared to the top 250 games on steam, more simulation games are, The wider bars also show an interesting aspect of the simulation genre as a whole.It shows that most of the top 250 games of the simulation genre don’t reach the same player counts as the action genre might. Additionally the graph shows that a few games sit at the top of Steam’s roster.

Scatter Plot - Player Engagement and Game Ownership

Visualization of previous correlation analysis between player engagement and estimated ownership

# create percent positive reviews
Top_250_Games <- Top_250_Games %>%
  mutate(Positive_PE = (Positive / (Positive + Negative)))
# Making the scatter plot with a log-transformed X-axis

ggplot(data = Top_250_Games, aes(x = Owners.avg, y = Positive_PE)) +
  geom_point(color = "grey2", alpha = 0.05, size = 2) +
  # Add the linear trendline using geom_smooth()
  geom_smooth(method = "lm", se = FALSE, color = "cadetblue4") +
  scale_x_log10() +
  labs(title = "Top 250 Games Positive Ratings %",
       x = "Estimated Owners (Log Scale)",
       y = "Percent Positive") +
  theme_minimal()

Graph Description

The above graph shows the percent of positive rating given for a game and the estimated owners for that game. The games in this plot are apart of the top 250 games on Steam. Games tend to have a percent positive rating of around 85% with the percentage slightly decreasing as there are less games down the line.

Scatter Plot Representing Reviews and Ownership

#Mutate whole dataset
Steam_Games <- Steam_Games %>%
  mutate(Positive_PE = (Positive / (Positive + Negative)))

# Making the scatter plot with a log-transformed X-axis

ggplot(data = Steam_Games, aes(x = Owners.avg, y = Positive_PE)) +
  geom_point(color = "mediumseagreen", alpha = 0.05, size = 2) +
  geom_smooth(method = "lm", se = FALSE, color = "darkgreen") + # Adds a linear trendline
  scale_x_log10() +
  labs(title = "Games Positive Ratings % ",
       x = "Estimated Owners (Log Scale)",
       y = "Percent Positive Ratio") +
  theme_minimal()

Graph description

This graph shows a similar trend to the previous graph but instead, it shows a slight increase from 75%. Additionally, as the number of owners increases the variety of ratings becomes more standard. This data is sourced from the whole data set rather than a subset like the previous set.

Graph: Price Pie Charts

# 1. Define the data (numeric vector of counts)
 #In Top_Games_250 use grepl to find all games with then save to Action_Games_from_250
F2P_Games_from_250 <- Top_250_Games[grepl("Free to Play", Top_250_Games$Genres), ]

# 2. Find percentages
Percent_F2P = round(((nrow(F2P_Games_from_250)/250)*100),2)
Not_Free = -Percent_F2P + 100

# 3. Making the counts variable
counts <- c(Percent_F2P, Not_Free)

# 2. Define the labels for the slices (character vector)
labels <- c("Free to Play", "Not Free to Play")

# 3. Define the colors
colors <- c("gray", "darkgray")

# 4. Generate the pie chart using the 'pie()' function
F2P_Pie_250 <- pie(
  x = counts,         # The numeric values
  labels = labels,    # The text labels for each slice
  main = "Percent Free to Play (Top 250)", # Main title       
  col = colors # Colors for the slices
) 


#Make Sim Free to play pie chart

# 1. Define the data (numeric vector of counts)
 #In Top_Games_250 use grepl to find all games with then save to Action_Games_from_250
F2P_Games_from_Sim <- Top_250_Sims[grepl("Free to Play", Top_250_Sims$Genres), ]

# 2. Find percentages
Percent_F2P2 = round(((nrow(F2P_Games_from_Sim)/250)*100),2)
Not_Free2 = -Percent_F2P2 + 100

# 3. Making the counts variable
counts <- c(Percent_F2P2, Not_Free2)

# 2. Define the labels for the slices (character vector)
labels <- c("Free to Play", "Not Free to Play")

# 3. Define the colors
colors <- c("cadetblue3", "cadetblue")

# 4. Generate the pie chart using the 'pie()' function
F2P_Pie_Sims <- pie(
  x = counts,         # The numeric values
  labels = labels,    # The text labels for each slice
  main = "Percent Free to Play (Top Sims)", # Main title       
  col = colors # Colors for the slices
) 


F2P_Pie_250
NULL
F2P_Pie_Sims
NULL
#Make Action Free to play pie chart

# 1. Define the data (numeric vector of counts)
 #In Top_Games_250 use grepl to find all games with then save to Action_Games_from_250
F2P_Games_from_Action <- Top_250_Action[grepl("Free to Play", Top_250_Action$Genres), ]

# 2. Find percentages
Percent_F2P3 = round(((nrow(F2P_Games_from_Action)/250)*100),2)
Not_Free3 = -Percent_F2P3 + 100

# 3. Making the counts variable
counts <- c(Percent_F2P3, Not_Free3)

# 2. Define the labels for the slices (character vector)
labels <- c("Free to Play", "Not Free to Play")

# 3. Define the colors
colors <- c("mediumseagreen", "darkgreen")

# 4. Generate the pie chart using the 'pie()' function
F2P_Pie_Action <- pie(
  x = counts,         # The numeric values
  labels = labels,    # The text labels for each slice
  main = "Percent Free to Play (Top Action)", # Main title       
  col = colors # Colors for the slices
) 


F2P_Pie_250
NULL
F2P_Pie_Sims
NULL
F2P_Pie_Action
NULL
Graph Descriptions:

Despite lower priced games being more accessible, the majority of games in each respective catagory are roughly 4 times more likely to not be free to play. Simulation games are the least likely to be free to play.

Exact Percents for above graph
print("Percent Free (250, Sim, Action) ")
[1] "Percent Free (250, Sim, Action) "
Percent_F2P
[1] 26.8
Percent_F2P2
[1] 18
Percent_F2P3
[1] 26
print("Percent Not Free (250, Sim, Action) ")
[1] "Percent Not Free (250, Sim, Action) "
Not_Free
[1] 73.2
Not_Free2
[1] 82
Not_Free3
[1] 74
Code Description

The above code shows the exact percentages for each of the pie charts.

Price Comparison

price_df <- data.frame(
  Games_Price = Top_250_Games$Price,
  Sims_Price = Top_250_Sims$Price,
  Action_Price = Top_250_Action$Price
)

summary(price_df)
  Games_Price      Sims_Price      Action_Price  
 Min.   : 0.00   Min.   : 0.000   Min.   : 0.00  
 1st Qu.: 0.00   1st Qu.: 2.115   1st Qu.: 0.00  
 Median : 9.99   Median :14.990   Median : 9.99  
 Mean   :15.89   Mean   :16.272   Mean   :16.54  
 3rd Qu.:24.99   3rd Qu.:24.990   3rd Qu.:24.99  
 Max.   :69.99   Max.   :59.990   Max.   :59.99  
Code Explanation:

This code provides numerical information about the price of each variable.

Price Box and Whisker Plot

# Convert the data frame to a long format
price_long <- pivot_longer(price_df, 
                                  cols = c(Games_Price, Sims_Price, Action_Price), 
                                  names_to = "Game_Type", 
                                  values_to = "Price")

# Create the box and whisker plot using ggplot2
ggplot(price_long, aes(x = Game_Type, y = Price, fill = Game_Type)) +
  geom_boxplot() +
  labs(title = "Price Distribution Across Game Types",
       y = "Price",
       x = "Game Type") +
  scale_fill_manual(values = c("mediumseagreen", "grey", "cadetblue3")) +
  theme_minimal() +
  stat_summary(fun = "median", 
               geom = "text", 
               aes(label = round(after_stat(y), 2)), # Rounds the median value (2 decimals for currency)
               vjust = -0.5, # Adjusts vertical position to be slightly above the median line
               color = "white")

Graph Description:

The graph shows that simulation games tend to be priced higher than other popular games. However, the most expensive games are floating around the most popular games.


# I found it interesting that the action and top games had a different max price by such a large margin and so I wanted to see what games cost the most in the top 250.

Most_Expensive_250 <- Top_250_Games[Top_250_Games$Price == max(price_df$Games_Price), ]

print(Most_Expensive_250)
ABCDEFGHIJ0123456789
 
 
AppID
<int>
Name
<chr>
Release.date
<chr>
Min.estimated.owners
<dbl>
Max.estimated.owners
<dbl>
Price
<dbl>
1551716740Starfield5-Sep-235e+061e+0769.99
NA
Code Explanation:

‘Starfield’ is a game by a major studio, Bethesda, and is an open world space simulation with realistic graphics that took around 7 years to develop.

Results

Description of Analysis

Regarding the first main question, the first P of the 4P’s is place. In this case, the place is Steam. The analysis will begin by looking at the distribution of genre tags among all games on Steam then counting games by their ownership. Estimated ownership is the best metric for success in my data set as there is no set quality value as it is a very complex subject. Using this variable, I decided to use it to look into the second P, product. In this case, the product is the genre because genres tend to have similarities and different target audiences making it a good measure for separating one product from another. For this question, a comparison of the estimated owners will be completed.

The third P, price, was an interesting aspect. First, the percentage of free to play games among the top 250, top simulation games, and top action games will be compared to each other to decide if the developer in the simulation genre could expect that free to play games in the Sims genre will perform better. After this, the prices for each game type will be analyzed through the use of a box and whisker plot. Despite the fourth P, promotion being Important, it was decided that the fourth P will not be covered as directly as the other three aspects. Funds spent on promotion is not an available value with this dataset, instead the other 3 will be the focus and this aspect may be considered more holistically with the assumption that game ownership in itself is a form of promotion.

Reasonsing behind methods of choice

The type of data analysis that was chosen to be the focus is bivariate. This method was chosen because most of the analysis surrounds comparison between two variables. It is believed that the answer to how necessary the 4P’s marketing method is on Steam can be measured by looking at estimated game ownership. This is the case because games are supported by their communities and games with strong communities tend to be both recommended by their players to other potential players and played on streaming sites which build interest in the game and build a strong community.

Through the analysis process it is important to keep in mind that different genres cater to different interests that fill niches, meaning there is no perfect game. In completing the analysis, the goal is to understand what Steam looks like for the majority of games on the platform and how expectations differ between genres regarding price and ownership. To find out what makes a game successful I first needed to run a correlation analysis to confirm that a strong community is the driving force behind an increase in most variables, this is what led me to sort by Ownership. The purpose of choosing the action genre to use as a comparison in addition to the top 250 games was to learn about what the majority of consumers on Steam prefer and using the variables as a basis for comparison. Using this method, the plan is to see if there are differences between genres on steam, following the Product quarter of the 4P’s.

Overall Findings

The simulation genre as a whole is a popular genre that is full of aspects that make the genre interesting to different types of players. These games often include a high level of player freedom meaning such games can be more expensive to produce. In this case, among the top 250 simulation games, the majority of those games have an average price of $14.99 with around only 20% of the games being free to play. With this in mind, simulation games tend to be complex and have long development times, driving prices up, this being said, it was found that games that are in the top 250 still do not reach Nintendo’s typical price with the most expensive game in the top 250 being 69.99 and ranking higher than only approximately 60% of the top games despite its high price tag.

There is a strong correlation between player engagement and the ownership of a game. Unexpectedly, the action genre and simulation games tend to have similar ownership. This was surprising to me because I postulated that players would spend time on games with more story-based aspects but what I found is that players will put time into what they are interested in whether the game is full of combat or a slow-paced farming game. Therefore, if a developer would like to make a game, building a strong community is the key to increasing ownership.

Conclusions

The Steam Platform as a whole is full of a wide variety of games that tend to lean closer to the indie developer as the platform is used to publish games rather than present a selected variety of games like the Nintendo store. The majority of games on this platform tend to see an estimated 1000 copies sold, however a few games reach estimated owners in the 10 millions. Steam responds best to the action genre and there are significant differences between the action and simulation genres. If a developer were looking to distribute a simulation game, the developer can expect that a successful Sim game based on game ownership would be different from an action game.

Regarding price, the data shows that the average price for a genre differs with action games tending to be priced around the $10 range and simulation games being priced around $14.99. This means that a game in the simulation genre being priced higher than the average popular game price is will not be out of the ordinary. Additionally, a game being free to play does not always lead to higher ownership. Overall, based on the percentage of positive reviews for games being rather consistent across all levels of ownership, it really is about being able to build a strong community and though marketing can be a really great boost a game will tend to make it to its intended audience, it really just depends on what level of ownership the developer is aiming for that changes the amount of effort and time that should be put into marketing because it is ultimately a good game is not measured only by its ownership.

Limitations of the data set would be the lack of total game revenue and a definite measure for the quality of a game. Additionally, which market the data comes from is not stated. If this variable were to be available, it would be interesting to complete an analysis comparing Steam’s stores for each country. An example of how this data may be used would be to compare how genres perform in different countries.

References

Going Indie Biz. (2024, July 27). Steam marketing expert reveals algorithm secrets [Video]. YouTube. https://www.youtube.com/watch?v=CfSThW3GwvM

Summer. (2025, March 17). The Four PS of Marketing: Definition, Role, and Questions to consider - Mageplaza. The Most Feature-rich Extension Developer for Magento 2 - Adobe Commerce. https://www.mageplaza.com/blog/4-ps-of-marketing.html

FronkonGames. “Steam Games Dataset.” Kaggle, 24 Aug. 2023, www.kaggle.com/datasets/fronkongames/steam-games-dataset.

“Simulation video game.” Wikipedia, 3 Nov. 2024, en.wikipedia.org/wiki/Simulation_video_game.

“Starfield (video game).” Wikipedia, 6 Nov. 2024, en.wikipedia.org/wiki/Starfield_(video_game).

“Steam Charts: Top 100.” Steam, store.steampowered.com/charts/. Accessed 9 Nov. 2025.

“Store Home.” Steam, store.steampowered.com/games. Accessed 9 Nov. 2025.

“Top questions.” Stack Overflow, stackoverflow.com/questions. Accessed 9 Nov. 2025.

“Why Are Games So Expensive Now? Factors Driving Up Game Prices.” DHgate Smart Blog, smart.dhgate.com/why-are-games-so-expensive-now-factors-driving-up-game-prices/. Accessed 9 Nov. 2025.

LS0tDQp0aXRsZTogIkZvdW5kYXRpb25zIE9mIERhdGEgQW5hbHl0aWNzIEZpbmFsIFByb2plY3QiDQphdXRob3I6ICJLYXRlbHluIENhcmxpbmkiDQpkYXRlOiAiMjAyNS0xMC0xOCINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KLS0tDQoNCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KDQojIExpYnJhcmllcw0KDQpgYGB7cn0NCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmxpYnJhcnkoc3RyaW5ncikNCmxpYnJhcnkoZ2dwbG90MikNCmBgYA0KDQojIFN1bW1hcnkNCg0KV2l0aCB0aGUgcHVycG9zZSBvZiBmaW5kaW5nIGhvdyBtdWNoIHRoZSA0UOKAmXMgb2YgbWFya2V0aW5nIGFmZmVjdCBnYW1lIG93bmVyc2hpcCBvbiBTdGVhbSBhbmQgaXRzIGltcG9ydGFuY2UsIDMgbWFpbiBxdWVzdGlvbnMgd2VyZSBhbmFseXplZC4gVGhlIHRocmVlIHF1ZXN0aW9ucyBhcmUgYXMgZm9sbG93czogd2hhdCBkb2VzIHRoZSBTdGVhbSBtYXJrZXQgbG9vayBsaWtlLCB3aWxsIHRoZSBnZW5yZSBhZmZlY3QgZ2FtZSBvd25lcnNoaXAsIGFuZCB3aGV0aGVyIHByaWNlIGV4cGVjdGF0aW9ucyBkaWZmZXIgYmV0d2VlbiBnZW5yZXMuDQoNClRoZSBkYXRhIHNldCBzb3VyY2VkIGZyb20gS2FnZ2xlIHdhcyBmaXJzdCBjbGVhbmVkIHVzaW5nIHRoZSBEcGx5ciBhbmQgVGlkeXZlcnNlIHBhY2thZ2VzLiBUaGVuLCBtb3ZpbmcgdG8gdGhlIGFuYWx5c2lzLCBrbm93aW5nIHRoYXQgU3RlYW0gaXMgYSBzaXRlIGZvciBkaXN0cmlidXRpbmcgZ2FtZXMgcmF0aGVyIHRoYW4gYSB2YXJpZXR5IG9mIHNlbGVjdGVkIGdhbWVzLCBpdCB3YXMgZGVjaWRlZCB0aGF0IG9mIHRoZSA0UOKAmXMsIHBsYWNlIHNob3VsZCBiZSB0aGUgZmlyc3QgYXNwZWN0IGNvbnNpZGVyZWQuIFdpdGggdGhlIG1ham9yaXR5IG9mIGdhbWVzIGhhdmluZyB2ZXJ5IGZldyBwbGF5ZXJzIGNvbXBhcmVkIHRvIHRoZSBtb3N0IHBvcHVsYXIgZ2FtZXMsIHRoZSBkYXRhIHNob3dlZCBhIG5lZ2F0aXZlIGV4cG9uZW50aWFsIGRpc3RyaWJ1dGlvbiwgbWVhbmluZyB0aGF0IHRvIGdhaW4gbm90b3JpZXR5IG9uIHN0ZWFtLCBnYW1lcyBuZWVkIHRvIGJlIG1hcmtldGVkIHdoaWNoIGJlZ2lucyB3aXRoIHRoZSBwcm9kdWN0LiBXaXRoIHRoaXMgaW5mb3JtYXRpb24gdGhlIG5leHQgc3RlcCB3YXMgdG8gbmFycm93IHRoZSBkYXRhIGFuZCBsb29rIGludG8gdGhlIHRvcCAyNTAgZ2FtZXMgYW5kIHRoZW4gZmluZCB0aGUgZ2VucmUgdGhhdCBhcHBlYXJlZCB0aGUgbW9zdCBpbiB0aGF0IHN1YnNldCwgdGhlIGFjdGlvbiBnZW5yZS4gQWZ0ZXJ3YXJkcyB0aGUgZm9jdXMgd2FzIHNoaWZ0ZWQgdG8gbG9vayBhdCBzdGVhbSBmcm9tIGEgZGV2ZWxvcGVyIGxvb2tpbmcgdG8gZGlzdHJpYnV0ZSBhIFNpbXVsYXRpb24gZ2FtZS4NCg0KSGF2aW5nIGFuYWx5emVkIHRoZSByZXN1bHRzLCBpdCB3YXMgZm91bmQgdGhhdCBnYW1lIG93bmVyc2hpcCBpcyBpbmRlZWQgYSBnb29kIG1ldHJpYyBmb3IgYSBzdWNjZXNzZnVsIGdhbWUgZHVlIHRvIGhvdyBtYW55IGFzcGVjdHMgc2hvdyBzdHJvbmcgY29ycmVsYXRpb25zIHRvIHRoZSBlc3RpbWF0ZWQgb3duZXJzaGlwIG9mIHRoZSBnYW1lLiBXaXRoIHRoaXMgaW4gbWluZCwgYW5hbHlzaXMgc2hvd3MgdGhhdCBzaW11bGF0aW9uIGdhbWVzIHRlbmQgdG8gZ2FybmVyIGxlc3MgcGxheWVycyB0aGFuIHRoZSBhY3Rpb24gZ2VucmUgQWRkaXRpb25hbGx5LCBnYW1lcyBpbiB0aGUgU2ltdWxhdGlvbiBnZW5yZSBhcmUgdHlwaWNhbGx5IHByaWNlZCBoaWdoZXIgdGhhbiB0aGUgbW9zdCBwb3B1bGFyIGdhbWVzIHNob3dpbmcgdGhhdCBzdWNoIGdhbWVzIHR5cGljYWxseSBhcmUgbW9yZSBjb21wbGV4IHRoYW4gZ2FtZXMgb25seSBpbiB0aGUgYWN0aW9uIGdlbnJlLiBLbm93aW5nIHRoaXMsIHRoZSBkYXRhIHNob3dzIHRoYXQgdGhlIGdlbnJlLCBvciBwcm9kdWN0IGluIG1hcmtldGluZyB0ZXJtcywgY2hhbmdlcyB0aGUgcHJpY2UgYW5kIGhvdyB3ZWxsIHRoZSBnYW1lIG1heSBiZSByZWNlaXZlZCBvbiBTdGVhbS4NCg0KIyBQdXJwb3NlDQoNClN0ZWFtIGlzIG9uZSBvZiB0aGUgbGFyZ2VzdCBvbmxpbmUgbWFya2V0cGxhY2VzIGZvciBQQyBnYW1lcyBvZmZlcmluZyBvdmVyIDEwMCwwMDAgZ2FtZXMgb24gdGhlIHBsYXRmb3JtLiBTdGVhbSBnYW1lIGNhdGFsb2d1ZSBpcyBtYXNzaXZlLCBtZWFuaW5nIHRoYXQgdGhlIG93bmVyc2hpcCBvZiBhIGdhbWUgaXMgbm90IG5lY2Vzc2FyaWx5IGluZGljYXRpdmUgb2YgaXRzIHF1YWxpdHkgb3IgZW5qb3ltZW50LCBtb3JlIHNvLCB0aGUgZ2FtZSBoYXMgYmVlbiBidXJpZWQuIFRoZSBwdXJwb3NlIG9mIHRoaXMgcHJvamVjdCBpcyB0byBzZWUgaG93IGdhbWVzIHBlcmZvcm0gb24gc3RlYW0gYnkgYW5hbHl6aW5nIHRoZSBwbGF0Zm9ybSBpdHNlbGYsIGxvb2tpbmcgdG8gc2VlIGlmIHRoZSBwcm9kdWN0IChnZW5yZSkgYWZmZWN0cyBvd25lcnNoaXAsIHRoZW4gc2VlaW5nIGlmIHByaWNlIGV4cGVjdGF0aW9ucyBjaGFuZ2UgYmV0d2VlbiBnZW5yZXMuIFdoYXQgZm9sbG93cyBpcyBhbiBvcmdhbml6ZWQgYXBwcm9hY2ggdG8gdGhlIGFuYWx5c2lzOg0KDQoxLiAgV2hhdCBkb2VzIFN0ZWFtIGxvb2sgbGlrZSBhcyBhIE1hcmtldCBwbGFjZQ0KMi4gIEhvdyBtdWNoIGRvZXMgdGhlIHByb2R1Y3QvZ2VucmUgbWF0dGVyIGNvbmNlcm5pbmcgZ2FtZSBvd25lcnNoaXA/DQozLiAgQXJlIHRoZXJlIGRpZmZlcmVudCBwcmljZSBleHBlY3RhdGlvbnMgYmV0d2VlbiBHZW5yZXM/DQoNClVzaW5nIHRoaXMgZGF0YSB0aGUgaG9wZSBpcyB0byBjcmVhdGUgYSBwcmVzZW50YXRpb24sIGZpbmQgaW5zcGlyYXRpb24sIGFuZCBtb3N0IGltcG9ydGFudGx5LCBwcmVzZW50IHRoZSBkYXRhIGluIGEgd2F5IHRoYXQgaXMgcmVhZGFibGUgYW5kIHVuZGVyc3RhbmRhYmxlLiBXaXRoIHRoZSBoZWxwIG9mIFIgU3R1ZGlvLCB0aGUgZ29hbCBpcyB0byBldmFsdWF0ZSB3aGV0aGVyIHVuZGVyc3RhbmRpbmcgdGhlIDRQcyBvZiBtYXJrZXRpbmcgY2FuIGhlbHAgZGV2ZWxvcGVycyBpbmNyZWFzZSBvd25lcnNoaXAgb2YgdGhlaXIgZ2FtZSBvbiBTdGVhbS4gVG8gZG8gdGhpcywgU3RlYW3igJlzIG1hcmtldHBsYWNlIHdpbGwgYmUgYW5hbHl6ZWQgZnJvbSB0aGUgcGVyc3BlY3RpdmUgb2YgYSBkZXZlbG9wZXIgbG9va2luZyB0byBwb3N0IGEgU2ltdWxhdGlvbiBnYW1lLCBieSBhbmFseXppbmcgdGhlIHRvcCBnZW5yZXMgYW5kIHBvcHVsYXIgZ2FtZXMsIGFuZCBkaXNjb3ZlcmluZyBob3cgbXVjaCBwbGFjZSwgcHJvZHVjdCwgYW5kIHByaWNlIG1hdHRlciBvbiB0aGUgcGxhdGZvcm0uDQoNCiMgRGF0YQ0KDQojIyBEaWN0aW9uYXJ5DQoNCnwgVmFyaWFibGUgTmFtZSB8IFdoYXQgdGhlIFZhcmlhYmxlIFJlcHJlc2VudHMgfCBOdW1lcmljYWwgb3IgQ2F0ZWdvcmljYWw/IHwNCnwtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS18LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tLS0tLS18DQp8IEFwcElEIHwgQXBwIElEIGlzIGEgdW5pcXVlIElEIHRoYXQgZW5hYmxlcyBTdGVhbSB0byBEaWZmZXJlbnRpYXRlIG9uZSBnYW1lIGZyb20gYW5vdGhlciBkZXNwaXRlIGl0cyBuYW1lIHwgTnVtZXJpY2FsIHwNCnwgTmFtZSB8IFRoZSBuYW1lIG9mIHRoZSBnYW1lIHwgQ2F0ZWdvcmljYWwgfA0KfCBFc3RpbWF0ZWQub3duZXJzIHwgVGhlIGVzdGltYXRlZCBudW1iZXIgb2YgcGVvcGxlIHdobyBvd24gdGhlIGdhbWUuIEdpdmVzIGEgcmFuZ2UgfCBDYXRlZ29yaWNhbCB8DQp8IFJlbGVhc2UuZGF0ZSB8IFRoZSBkYXRlIHRoZSBnYW1lIHJlbGVhc2VkIHwgQ2F0ZWdvcmljYWwgfA0KfCBQcmljZSB8IFRoZSBiYXNlIHByaWNlIG9mIHRoZSBnYW1lIHwgQ2F0ZWdvcmljYWwgfA0KfCBTdXBwb3J0ZWQubGFuZ3VhZ2VzIHwgRGV0YWlscyB0aGUgbGFuZ3VhZ2VzIHRoYXQgYXJlIHN1cHBvcnRlZCBieSB0aGUgZ2FtZSB8IENhdGVnb3JpY2FsIHwNCnwgVXNlci5zY29yZSB8IFN0ZWFtJ3Mgd2F5IG9mIHN1bW1hcml6aW5nIHBsYXllciByZWNvbW1lbmRhdGlvbnMuIEl0IGlzIGEgUGVyY2VudGFnZSBjYWxjdWxhdGVkIGJ5IGZpbmRpbmcgdGhlIG51bWJlciBvZiBwb3NpdGl2ZSByZXZpZXdzIHRoZW4gZGl2aWRpbmcgYnkgdG90YWwgcmV2aWV3cyB8IE51bWVyaWNhbCB8DQp8IFBvc2l0aXZlIHwgTnVtYmVyIG9mIHBvc2l0aXZlIHJldmlld3MgfCBOdW1lcmljYWwgfA0KfCBOZWdhdGl2ZSB8IE51bWJlciBvZiBuZWdhdGl2ZSByZXZpZXdzIHwgTnVtZXJpY2FsIHwNCnwgQWNoaWV2ZW1lbnRzIHwgTnVtYmVyIG9mIGFjaGlldmVtZW50cyBhdmFpbGFibGUgaW4gdGhlIGdhbWUgfCBOdW1lcmljYWwgfA0KfCBSZWNvbW1lbmRhdGlvbnMgfCBOdW1iZXIgb2YgcmVjb21tZW5kYXRpb25zIHwgTnVtZXJpY2FsIHwNCnwgQXZlcmFnZS5wbGF5dGltZS50d28gd2Vla3MgfCBBdmVyYWdlIHBsYXkgdGltZSBvdmVyIHR3byB3ZWVrIG1lYXN1cmVkIGluIGhvdXJzIHwgTnVtZXJpY2FsIHwNCnwgQXZlcmFnZS5wbGF5dGltZS5mb3JldmVyIHwgQXZlcmFnZSB0b3RhbCBwbGF5dGltZSB8IE51bWVyaWNhbCB8DQp8IE1lZGlhbi5wbGF5dGltZS50d28ud2Vla3MgfCBNZWRpYW4gcGxheXRpbWUgb3ZlciB0d28gd2Vla3MgKGxlc3Mgc3VzY2VwdGlibGUgdG8gb3V0bGllcnMpIHwgTnVtZXJpY2FsIHwNCnwgTWVkaWFuLnBsYXl0aW1lLmZvcmV2ZXIgfCBNZWRpYW4gdG90YWwgcGxheXRpbWUgfCBOdW1lcmljYWwgfA0KfCBEZXZlbG9wZXJzIHwgVGhlIGRldmVsb3BlcnMgb2YgdGhlIGdhbWUgfCBDYXRlZ29yaWNhbCB8DQp8IFB1Ymxpc2hlcnMgfCBUaGUgcHVibGlzaGVycyBvZiB0aGUgZ2FtZSB8IENhdGVnb3JpY2FsIHwNCnwgQ2F0ZWdvcmllcyB8IERlbm90ZXMgd2hhdCBraW5kIG9mIGdhbWUgaXQgaXMgKG9ubGluZSwgc2luZ2xlLXBsYXllciwgZWN0LikgfCBDYXRlZ29yaWNhbCB8DQp8IEdlbnJlcyB8IERlbm90ZXMgdGhlIG11bHRpcGxlIGdlbnJlcyBvZiB0aGUgZ2FtZSB8IENhdGVnb3JpY2FsIHwNCnwgVGFncyB8IE1vcmUgc3BlY2lmaWMgdGhhbiAnR2VucmVzJyAoY2xpY2tlciwgYWdyaWN1bHR1cmUsIHNhbmRib3gpIHwgQ2F0ZWdvcmljYWwgfA0KDQojIyBNaXNzaW5nL05BL051bGwgVmFyaWFibGVzDQoNClRoZSBEYXRhIHdhcyBzY3JhcGVkIGZyb20gU3RlYW0gbWVhbmluZyB0aGVyZSBhcmUgbWFueSB2YWx1ZXMgdGhhdCBoYXZlIG9kZCBmb3JtYXR0aW5nLiBPcmlnaW5hbGx5LCBpdCB3YXMgYmVsaWV2ZWQgdGhpcyB3YXMgYW4gaXNzdWUgd2l0aCBob3cgdGhlIGRhdGEgd2FzIGdhdGhlcmVkIGFuZCB0aGF0IHRob3NlIHZhbHVlcyB3ZXJlIFRoaXMgYmVpbmcgc2FpZCwgYWZ0ZXIgc29tZSByZXNlYXJjaCBpdCB3YXMgZm91bmQgdGhhdCB0aGUgc3ltYm9scyBpbiB0aGUg4oCcTmFtZeKAnSBjb2x1bW4gd2FzIGEgZm9ybSBvZiBVbmljb2RlIGFuZCB0aGUgdGV4dCBpcyBwZXJmZWN0bHkgZGVjaXBoZXJhYmxlLiBUaGlzIG9jY3VycyBhcyBhIHJlc3VsdCBvZiB1c2luZyBjaGFyYWN0ZXJzIGZyb20gZGlmZmVyZW50IGxhbmd1YWdlcy4gQ2hhbmdpbmcgdGhvc2UgdmFsdWVzIGludG8gVW5pY29kZSBpcyB0aGUgY29tcHV0ZXLigJlzIHdheSBvZiByZXByZXNlbnRpbmcgY2hhcmFjdGVycyBmcm9tIGFsbW9zdCBhbGwgb2YgdGhlIHdvcmxkIHdyaXR0ZW4gbGFuZ3VhZ2VzLiBJbiBlc3NlbmNlLCB0aGUgVW5pY29kZSBwcmVzZW50IGluIHRoZSBkYXRhIGlzIG5vdCBhIHJlc3VsdCBvZiBiYWQgc2NyYXBpbmcuIFRoaXMgYmVpbmcgc2FpZCwgYSBmZXcgTkEgdmFsdWVzIHdlcmUgZm91bmQsIGJ1dCB0aGVzZSB2YWx1ZXMgaGF2ZSBsaXR0bGUgYWZmZWN0IG9uIHRoZSBjYWxjdWxhdGlvbnMgYW5kIGhhdmUgcG9zZWQgbGl0dGxlIHByb2JsZW1zIG91dHNpZGUgb2YgdGhlIHVzZXIgc2NvcmUgY29ycmVsYXRpb24gYW5hbHlzaXMuIFRoaXMgY29sdW1uIHNob3dlZCBzb21lIG1ham9yIE5BIHZhbHVlczsgaG93ZXZlciwgdGhpcyB3b3VsZCBvbmx5IGJlIGEgcHJvYmxlbSBpZiBpdCB3YXMgZGVjaWRlZCB0byBsb29rIG91dHNpZGUgb2YgdGhlIHByb2plY3Qgc2NvcGUuDQoNCiMjIyBNZXRob2RvbG9neSBmb3IgQ2xlYW5pbmcgdGhlIGRhdGENCg0KVGhlIGRhdGEgaXMgcmF0aGVyIHRpZHkgd2l0aCB0aGUgZXhjZXB0aW9uIG9mIHRoZSBHZW5yZXMgQ29sdW1uLiBUaGUgR2VucmVzIGNvbHVtbiBjb250YWlucyBhIGxpc3Qgb2YgdGFnZ2VkIGdlbnJlcyByYXRoZXIgdGhhbiBhIHNpbmdsZSB2YWx1ZS4gSSBkZWNpZGVkIHRvIGxlYXZlIHRoZSBHZW5yZXMgY29sdW1uIGFsb25lIGJlY2F1c2UgbXVjaCBvZiB0aGUgYW5hbHlzaXMgd2lsbCByZWx5IG9uIHRoYXQgc2luZ2xlIGNvbHVtbi4gSWYgdGhlIHZhbHVlcyB3ZXJlIHRvIGJlIHNlcGFyYXRlZCwgdGhlIGFtb3VudCBvZiBjb2x1bW5zIHBlciByb3cgd291bGQgYmUgZGlmZmVyZW50IGR1ZSB0byBTdGVhbSdzIGFsbG93YW5jZSBvZiBtdWx0aXBsZSBnZW5yZSB0YWdzLiBJbiBjb25zaWRlcmF0aW9uIG9mIG5lZWRpbmcgdG8ga2VlcCB0aGUgZGF0YSB0b2dldGhlciwgdGhlIGdyZXBsKCkgZnVuY3Rpb24gd2lsbCBiZSBhIGJpZyBoZWxwIHRoZSBmb2N1cyBpcyBuYXJyb3dlZCB0byBzcGVjaWZpYyBnZW5yZXMgd2l0aGluIHRoZSBjb2x1bW4uIFRoZSBmdW5jdGlvbiBhbGxvd3MgUiB0byBmaW5kIHNwZWNpZmljIHN0cmluZ3Mgd2l0aGluIGNvbHVtbnMgcmF0aGVyIHRoYW4gc3BsaXR0aW5nIHRoZSBnZW5yZXMgY29sdW1uIGFzIHdpbGwgYmUgZG9uZSB0byBmaW5kIHRoZSBtb3N0IGNvbW1vbiBnZW5yZXMgb24gU3RlYW0uDQoNClRob3VnaCB0aGUgZGF0YSBpcyB2ZXJ5IGNvbnNpc3RlbnQsIHRoZXJlIGFyZSBhIGZldyBkaWZmaWN1bHRpZXMgaW4gcGxhY2VzIHdoZXJlIHRleHQgaXMgZm9ybWF0dGVkLCBwYXJ0aWN1bGFybHkgd2hlbiBpdCBjb21lcyB0byBnYW1lcyB3aXRoIHNwZWNpYWwgY2hhcmFjdGVycyBvciBmb3JtYXR0aW5nIG5vdCBhdmFpbGFibGUgb24gdGhlIHR5cGljYWwgRW5nbGlzaCBrZXlib2FyZC4gVGhpcyBpcyBvbmx5IGEgbWlub3IgY29udmVuaWVuY2UgYmVjYXVzZSB0aGUgdGV4dCBjYW4gc3RpbGwgYmUgZGVjb2RlZC4gQWRkaXRpb25hbGx5LCB0aGVyZSBhcmUgYSBmZXcgY29sdW1ucyB0aGF0IGNvdWxkIGJlIGJldHRlciB1dGlsaXplZCBpZiB0aGV5IHdlcmUgbnVtZXJpY2FsIHZhbHVlcy4gVGhlIG1haW4gb2ZmZW5kZXIgaXMgdGhlIGVzdGltYXRlZCBvd25lcuKAmXMgY29sdW1uLiBUbyBmaXggdGhpcyBpc3N1ZSwgdGhlIHZhbHVlcyB3aWxsIGJlIHNlcGFyYXRlZCBpbnRvIG1pbiBhbmQgbWF4IHRoZW4gdGhlIGF2ZXJhZ2Ugb2YgYm90aCB3aWxsIGJlIG11dGF0ZWQgaW50byBhIG5ldyBjb2x1bW4gd2hpY2ggbW9zdCBvZiB0aGUgYW5hbHlzaXMgd2lsbCBiZSBjb21wbGV0ZWQgd2l0aC4NCg0KYGBge3J9DQojNGEuIFJlYWQgaW4gZGF0YQ0KDQpPR19TdGVhbSA8LSByZWFkLmNzdigiU3RlYW1fR2FtZXMuY3N2IiwgZmlsbCA9IFRSVUUpDQoNCk9HX1N0ZWFtDQoNCmBgYA0KDQpgYGB7cn0NCiM0Yi4xIHNob3cgYSBzdW1tYXJ5IG9mIHRoZSBkYXRhIGFuZCB0aGUgZmlyc3QgZmV3IG9ic2VydmF0aW9ucw0KDQojU3VtbWFyeQ0Kc3VtbWFyeShPR19TdGVhbSkNCg0KIyBUaGlzIG5lZWRlZCB0byBiZSBzaG93biBpbiBhIG5ldyB3aW5kb3cNCmhlYWQoT0dfU3RlYW0pDQpgYGANCg0KYGBge3J9DQojNGIuMiBGaXJzdCBmZXcgb2JzZXJ2YXRpb25zDQpoZWFkKE9HX1N0ZWFtKQ0KDQpgYGANCg0KYGBge3J9DQojNGMuIENyZWF0ZSBhIG5ldyBkYXRhIHNldCBmcm9tIHRoZSB2YXJpYWJsZXMgdGhhdCBhcmUgb2YgaW50ZXJlc3QNCg0KU3RlYW1fR2FtZXNfUHJlIDwtIE9HX1N0ZWFtICU+JQ0KICBzZWxlY3QoQXBwSUQsIE5hbWUsIFJlbGVhc2UuZGF0ZSwgRXN0aW1hdGVkLm93bmVycywgUHJpY2UsIFN1cHBvcnRlZC5sYW5ndWFnZXMsIFVzZXIuc2NvcmUsIFBvc2l0aXZlLCBOZWdhdGl2ZSwgQWNoaWV2ZW1lbnRzLCBSZWNvbW1lbmRhdGlvbnMsIEF2ZXJhZ2UucGxheXRpbWUudHdvLndlZWtzLCBBdmVyYWdlLnBsYXl0aW1lLmZvcmV2ZXIsIE1lZGlhbi5wbGF5dGltZS50d28ud2Vla3MsIE1lZGlhbi5wbGF5dGltZS5mb3JldmVyLCBEZXZlbG9wZXJzLCBQdWJsaXNoZXJzLCBDYXRlZ29yaWVzLCBHZW5yZXMsIFRhZ3MpDQoNCiNFeGFtcGxlIG9mIGhvdyB0aGlzIGRhdGFzZXQgbWF5IGJlIHVzZWQNCg0KUHVibGlzaGVyX1ByaWNlX1N1bW1hcnkgPC0gU3RlYW1fR2FtZXNfUHJlJT4lDQogIGdyb3VwX2J5KFB1Ymxpc2hlcnMpICU+JQ0KICBzdW1tYXJpc2UoQXZnX1ByaWNlID0gbWVhbihQcmljZSkpICU+JQ0KICBhcnJhbmdlKC1BdmdfUHJpY2UpDQpQdWJsaXNoZXJfUHJpY2VfU3VtbWFyeQ0KDQpzdW1tYXJ5KFN0ZWFtX0dhbWVzX1ByZSkNCg0KYGBgDQoNCmBgYHtyfQ0KIzRkLiBOYW1lIHRoZSBuZXcgZGF0YXNldCBhbmQgd3JpdGUgaXQgdG8gYSBjc3YgZmlsZQ0KDQp3cml0ZS5jc3YoU3RlYW1fR2FtZXNfUHJlLCAiU3RlYW1fR2FtZXNfQ2xlYW5lZC5jc3YiKQ0KYGBgDQoNCiMgRGF0YSBQcmUtcHJvY2Vzc2luZw0KDQpgYGB7cn0NCiMgUmVhZCBpbiBEYXRhDQpTdGVhbV9HYW1lcyA8LSByZWFkLmNzdigiU3RlYW1fR2FtZXNfQ2xlYW5lZC5jc3YiKQ0KDQpTdGVhbV9HYW1lcw0KYGBgDQoNCmBgYHtyfQ0KIyBHZXQgcmlkIG9mICdYJyBjb2x1bW4gZnJvbSBTdGVhbV9HYW1lc19DbGVhbmVkDQoNClN0ZWFtX0dhbWVzJFggPC0gTlVMTA0KYGBgDQoNCmBgYHtyfQ0KIyBGaW5kIHRoZSBjb2x1bW4gbmFtZXMNCmNvbG5hbWVzKFN0ZWFtX0dhbWVzKQ0KYGBgDQoNCiMjIyBTdW1tYXJ5IFN0YXRpc3RpY3MNCg0KYGBge3J9DQojIFN1bW1hcnkgU3RhdGlzdGljcw0KDQpzdW1tYXJ5KFN0ZWFtX0dhbWVzX1ByZSkNCmBgYA0KDQpDdXJyZW50bHkgdGhlIGVzdGltYXRlZCBvd25lcnMgY29sdW1uIGlzIGluIGEgY2hhcmFjdGVyIGZvcm1hdCBtZWFuaW5nIGl0IHdpbGwgbmVlZCB0byBiZSBjb252ZXJ0ZWQgdG8gYSBudW1lcmljYWwgZGF0YXR5cGUuDQoNCiMjIyMgRGF0YSBEaW1lbnNpb25zDQoNCmBgYHtyfQ0KIyBVc2UgZGltIChvdXRjb21lIGlzIDEwOTc4MCByb3dzIGFuZCAyMCBjb2x1bW5zKQ0KDQpkaW0oU3RlYW1fR2FtZXMpDQpgYGANCg0KVGhlcmUgYXJlIDEwOTc4MCByb3dzIGluIHRoaXMgZGF0YSBzZXQgYW5kIDIwIGNvbHVtbnMuDQoNCiMgRGF0YSBFeHBsb3JhdGlvbg0KDQojIyMgQmFyIEdyYXBoOiBQbGF5ZXIgQ291bnQNCg0KYGBge3J9DQoNCiMgVXBkYXRlIGRhdGEgc2V0IHNvIG1pbiBhbmQgbWF4IGVzdGltYXRlZCBwbGF5ZXJzIGhhdmUgdGhlaXIgb3duIGNvbHVtbnMNCg0KU3RlYW1fR2FtZXMgPC0gU3RlYW1fR2FtZXMgJT4lDQogIHNlcGFyYXRlKA0KICAgIGNvbCA9IEVzdGltYXRlZC5vd25lcnMsDQogICAgaW50byA9IGMoJ01pbi5lc3RpbWF0ZWQub3duZXJzJywgJ01heC5lc3RpbWF0ZWQub3duZXJzJyksDQogICAgc2VwID0gIi0iLA0KICApDQogIA0KYGBgDQoNCmBgYHtyfQ0KI0NvbnZlcnQgQ29sdW1ucyB0byBudW1lcmljYWwgdmFsdWUNCg0KU3RlYW1fR2FtZXMkTWF4LmVzdGltYXRlZC5vd25lcnMgPC0gYXMubnVtZXJpYyhTdGVhbV9HYW1lcyRNYXguZXN0aW1hdGVkLm93bmVycykNCg0KU3RlYW1fR2FtZXMkTWluLmVzdGltYXRlZC5vd25lcnMgPC0gYXMubnVtZXJpYyhTdGVhbV9HYW1lcyRNaW4uZXN0aW1hdGVkLm93bmVycykNCmBgYA0KDQpgYGB7cn0NCiNDb252ZXJ0IGJhY2sgdG8gYXZlcmFnZSBlc3RpbWF0ZWQgb3duZXJzIChtb3N0IGxpa2VseSB2YWx1ZSkNCg0KU3RlYW1fR2FtZXMgPC0gU3RlYW1fR2FtZXMgJT4lDQogIG11dGF0ZShPd25lcnMuYXZnID0gKE1pbi5lc3RpbWF0ZWQub3duZXJzICsgTWF4LmVzdGltYXRlZC5vd25lcnMpIC8gMikNCg0KaGVhZChTdGVhbV9HYW1lcyRPd25lcnMuYXZnLCAxNSkNCmBgYA0KDQpgYGB7cn0NCmdncGxvdChkYXRhID0gU3RlYW1fR2FtZXMsIGFlcyh4ID0gT3duZXJzLmF2ZykpICsNCiAgZ2VvbV9iYXIoZmlsbCA9ICJjYWRldGJsdWUzIiwgY29sb3IgPSAiY2FkZXRibHVlIikgKyANCiAgIGxhYnMoDQogICAgdGl0bGUgPSAiTnVtYmVyIG9mIEdhbWVzIGJ5IExvZyBvZiBFc3RpbWF0ZWQgT3duZXJzIiwNCiAgICB5ID0gIk51bWJlciBvZiBHYW1lcyIsDQogICAgeCA9ICJFc3RpbWF0ZWQgT3duZXJzIg0KICAgKSArDQogICBzY2FsZV94X2xvZzEwKCkNCg0KYGBgDQoNCiMjIyMgR3JhcGggRGVzY3JpcHRpb246DQoNClRoZSBncmFwaCBzaG93cyB0aGF0IGFuIG92ZXJ3aGVsbWluZ2x5IGxhcmdlIGFtb3VudCBvZiBnYW1lcyBvbiBzdGVhbSBoYXZlIGEgc21hbGwgcGxheWVyIGJhc2UuIFRoaXMgY29uZmlybXMgdGhhdCBhIHBsYXllciBiYXNlIG9mIGFyb3VuZCAxMDAwIHBsYXllcnMgaXMgY29uc2lkZXJlZCB0byBiZSBhYm91dCBhdmVyYWdlIGZvciBzbWFsbGVyIGdhbWUgc3R1ZGlvcyBvbiBzdGVhbSByZWdhcmRsZXNzIG9mIGdlbnJlLg0KDQojIyMgVG9wIDggTW9zdCBDb21tb24gR2VucmVzIG9uIFN0ZWFtDQoNCmBgYHtyfQ0KIyBTcGxpdHRpbmcgdGhlIHZhbHVlcyBmcm9tIHRoZSAnR2VucmVzJyBjb2x1bW4NCkdlbnJlcyA8LSBkYXRhLmZyYW1lKA0KICBHZW5yZXMgPSBTdGVhbV9HYW1lcyRHZW5yZXMNCikNCg0KR2VucmVzX1NwbGl0IDwtIEdlbnJlcyAlPiUNCiAgc2VwYXJhdGVfbG9uZ2VyX2RlbGltKEdlbnJlcywgZGVsaW0gPSAiLCIpDQoNCkdlbnJlc19TcGxpdA0KDQpgYGANCg0KYGBge3J9DQojIEZpbmQgdGhlIGNvdW50IGZvciBlYWNoIEdlbnJlDQoNCiAgICBHZW5yZXNfQ291bnQgPC0gR2VucmVzX1NwbGl0ICU+JQ0KICAgICAgY291bnQoR2VucmVzLCBzb3J0ID0gVFJVRSkNCg0KIyBGaW5kIHRvcCA4IGdlbnJlDQoNCiAgICBUb3BfOF9HZW5yZXMgPC0gR2VucmVzX0NvdW50ICU+JQ0KICAgICAgc2xpY2VfaGVhZChuID0gOCkNCiAgICANCiMgUHJpbnQgdG9wIDgNCiAgICANCnByaW50KFRvcF84X0dlbnJlcykNCmBgYA0KDQpgYGB7cn0NClRvcF84X1ZlYyA8LSBjKCJJbmRpZSIsICJDYXN1YWwiLCAiQWN0aW9uIiwgIkFkdmVudHVyZSIsICJTaW11bGF0aW9uIiwgIlN0cmF0ZWd5IiwgIlJQRyIsICJFYXJseSBBY2Nlc3MiKQ0KDQpHZW5yZXNfRmlsdGVyIDwtIEdlbnJlc19TcGxpdCAlPiUNCiAgZmlsdGVyKEdlbnJlc19TcGxpdCA9PSBUb3BfOF9WZWMpDQoNCnByaW50KEdlbnJlc19GaWx0ZXIpDQpgYGANCg0KYGBge3J9DQojIFN1bW1hcml6ZSBnZW5yZSBjb3VudHMgYW5kIGNhbGN1bGF0ZSBwZXJjZW50YWdlcw0KR2VucmVzX0ZpbHRlciA8LSBHZW5yZXNfRmlsdGVyICU+JQ0KICBjb3VudChHZW5yZXMpICU+JQ0KICBtdXRhdGUoUGVyY2VudGFnZSA9IHJvdW5kKChuIC8gc3VtKG4pKSAqIDEwMCwgMSkpDQoNCiMgUGllIGNoYXJ0IHdpdGggcGVyY2VudGFnZSBsYWJlbHMNCmdncGxvdChHZW5yZXNfRmlsdGVyLCBhZXMoeCA9ICIiLCB5ID0gbiwgZmlsbCA9IEdlbnJlcykpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIGNvbG9yID0gIndoaXRlIikgKw0KICBjb29yZF9wb2xhcih0aGV0YSA9ICJ5IikgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gcGFzdGUwKFBlcmNlbnRhZ2UsICIlIikpLA0KICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9zdGFjayh2anVzdCA9IDAuNSksDQogICAgICAgICAgICBjb2xvciA9ICJ3aGl0ZSIsIHNpemUgPSAzLjUpICsNCiAgbGFicygNCiAgICB0aXRsZSA9ICJNb3N0IENvbW1vbiBHZW5yZXMgb24gU3RlYW0gKFBpZSBDaGFydCkiLA0KICAgIHggPSBOVUxMLA0KICAgIHkgPSBOVUxMLA0KICAgIGZpbGwgPSAiR2VucmUiDQogICkgKw0KICB0aGVtZV92b2lkKCkgKw0KICB0aGVtZSgNCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBmYWNlID0gImJvbGQiKSwNCiAgICBsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiDQogICkgKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJjYWRldGJsdWUyIiwiY2FkZXRibHVlMyIsICJjYWRldGJsdWUiLCJjYWRldGJsdWU0IiwibWVkaXVtc2VhZ3JlZW4iLCAic2VhZ3JlZW4iLCJncmVlbjQiLCJkYXJrZ3JlZW4iKSkNCmBgYA0KDQojIyMjIEdyYXBoIERlc2NyaXB0aW9uOg0KDQpUaGUgYWJvdmUgZ3JhcGggc2hvd3MgaG93IG1hbnkgZ2FtZXMgb24gc3RlYW0gYXJlIGNhdGVnb3JpemVkIHVuZGVyIGRpZmZlcmVudCBnZW5yZXMuIFRoaXMgZ3JhcGggaW4gcGFydGljdWxhciBvbmx5IHNob3dzIHRoZSB0b3AgOCBnZW5yZXMgZHVlIHRvIGhvdyBtYW55IGdhbWVzIHVzZSB0aGVzZSBnZW5yZSB0YWdzIHNwZWNpZmljYWxseS4gVGhlIGluZGllIGdlbnJlIGlzIHRoZSBtb3N0IHBvcHVsYXIgdGFnLiBUaGlzIHNob3dzIHRoYXQgbW9zdCBnYW1lcyBvbiBTdGVhbSBhcmUgbWFkZSBieSBpbmRlcGVuZGVudCBkZXZlbG9wZXJzLiBBZGRpdGlvbmFsbHksIGl0IHNlZW1zIHRoYXQgbWFueSBnYW1lcyB1c2UgdGhlIGNhc3VhbCB0YWcuDQoNCiMjIyMgRmluZGluZyBteSBQcmVmZXJyZWQgR2FtZXMNCg0KVGhlICdQcmVmZXJyZWRfR2FtZXMnIHZlY3RvciBjb250YWlucyBnYW1lcyB0aGF0IEkgZmluZCB0byBiZSBlbmFnYWdpbmcgYW5kIGVuam95YWJsZS4gV2l0aCB0aGUgZ29hbCBvZiBmaW5kaW5nIHdoaWNoIGdlbnJlIEkgbGVhbiB0b3dhcmRzIHRoZSBtb3N0LiBFdmVyeSBnZW5yZSBpcyBkaWZmZXJlbnQsIENob29zaW5nIGEgZ2VucmUgSSBrbm93IHRoZSBtb3N0IGFib3V0IHdpbGwgaGVscCBtZSBpZGVudGlmeSBrZXkgYXNwZWN0cyB0aGF0IG1ha2UgdGhvc2UgZ2FtZXMgc3RhbmQgb3V0IGFtb25nDQoNCmBgYHtyfQ0KIyBQcmVmZXJyZWQgR2FtZXMgDQojIENoZWNrIE5hbWVzIChOb3QgY2hlY2tlZCkNCg0KUHJlZmVycmVkX0dhbWVzIDwtIGMoIkNpbm5hYnVubnkiLCAiUG90aW9uIENyYWZ0OiBBbGNoZW1pc3QgU2ltdWxhdG9yIiwgIlN0YXJkZXcgVmFsbGV5IiwgIkNpdGllczogU2t5bGluZXMiLCAiR29vZCBQaXp6YSwgR3JlYXQgUGl6emEgLSBDb29raW5nIFNpbXVsYXRvciBHYW1lIiwgIlBhcGEncyBGcmVlemVyaWEgRGVsdXhlIiwgIlN0aWNreSBCdXNpbmVzcyIsICJTbGltZSBSYW5jaGVyIDIiLCAiQWxiaW9uIE9ubGluZSIsICJTcXVpcnJlbGVkIEF3YXkiKQ0KDQojZ3JhYiBnYW1lcw0KDQpGYXZvcml0ZV9HYW1lcyA8LSBTdGVhbV9HYW1lcyAlPiUNCiAgZmlsdGVyKE5hbWUgJWluJSBQcmVmZXJyZWRfR2FtZXMpDQoNCiNwcmludCBmYXZvcml0ZSBnYW1lcw0KRmF2b3JpdGVfR2FtZXMNCmBgYA0KDQojIyMgQ29ycmVsYXRpb24gQW5hbHlzaXMgb24gdG9wIDI1MCBnYW1lcw0KDQpgYGB7cn0NCiMgRmluZCB0aGUgdG9wIDI1MCBnYW1lcyBpbiB0aGUgU3RlYW0gbGlicmFyeQ0KDQpUb3BfMjUwX0dhbWVzIDwtIFN0ZWFtX0dhbWVzICU+JQ0KICBhcnJhbmdlKGRlc2MoT3duZXJzLmF2ZykpICU+JQ0KICANCiAgaGVhZCgyNTApDQoNCmNvcnJlbGF0aW9uX21hdHJpeF8yNTAgPC0gVG9wXzI1MF9HYW1lcyAlPiUNCiAgc2VsZWN0KA0KICAgIE93bmVycy5hdmcsIFByaWNlLCBQb3NpdGl2ZSwgTmVnYXRpdmUsIA0KICAgICAgICAgQWNoaWV2ZW1lbnRzLCBSZWNvbW1lbmRhdGlvbnMsIA0KICAgICAgICAgQXZlcmFnZS5wbGF5dGltZS50d28ud2Vla3MsIEF2ZXJhZ2UucGxheXRpbWUuZm9yZXZlcikgJT4lDQogIG11dGF0ZShhY3Jvc3MoZXZlcnl0aGluZygpLCBhcy5udW1lcmljKSkgJT4lICAjIGNvbnZlcnRzIGFsbCBjb2x1bW5zIHRvIHRoZSBudW1lcmljIGRhdGF0eXBlDQogIGNvcih1c2UgPSAicGFpcndpc2UuY29tcGxldGUub2JzIikgICAgICAgICAgICAjIGhhbmRsZXMgbWlzc2luZyB2YWx1ZXMNCg0KY29ycmVsYXRpb25fbWF0cml4XzI1MA0KYGBgDQoNCiMjIyMjIEtleSBDb3JyZWxhdGlvbnMgYW5kIFRob3VnaHRzDQoNCkJhc2VkIG9uIHRoaXMgY29ycmVsYXRpb24gbWF0cml4LCBJIHdvdWxkIGxpa2UgdG8gZm9jdXMgb24gMyBkaWZmZXJlbnQgYXNwZWN0cyBmb3IgZnVydGhlciBhbmFseXNpczsgT3duZXJzLmF2ZywgcGxheWVyIGVuZ2FnZW1lbnQgb2YgYWxsIGtpbmRzIChQb3NpdGl2ZSwgTmVnYXRpdmUsIGFuZCBSZWNvbW1lbmRhdGlvbnMpLCBhbmQgUHJpY2UuIE93bmVycy5hdmcgaGFzIHRoZSBiaWdnZXN0IGltcGFjdCBvbiBldmVyeSBhc3BlY3Qgb2YgdGhlIGdhbWUgd2hpbGUgcGxheWVyIGVuZ2FnZW1lbnQgc2VlbXMgdG8gZHJpdmUgaG93IG1hbnkgY29waWVzIG9mIHRoZSBnYW1lIGFyZSBzb2xkLiBUaG91Z2ggdGhlIHByaWNlIGNvbHVtbiBkb2VzIG5vdCBzZWVtIHRvIGhhdmUgYW55IHN0cm9uZyBjb3JyZWxhdGlvbnMsIGl0IGlzIHRoZSBhc3BlY3Qgd2l0aCB0aGUgbW9zdCBzbGlnaHRseSBuZWdhdGl2ZSByZWxhdGlvbnNoaXBzIGluIG1vc3QgYXNwZWN0cyB3aGlsZSBpbmNyZWFzaW5nIGZvcmV2ZXIgcGxheXRpbWUuDQoNCiMjIyBDb21wYXJpc29uIERhdGEgVmlzdWFsaXNhdGlvbnMNCg0KIyMjIyBUb3BfMjUwIGZvciBDb21wYXJpc29uDQoNCkZvciBteSBuZXh0IHNlcmllcyBvZiBhbmFseXNpcyBJIGNob3NlIHRvIGZvY3VzIG9uIHRoZSBUb3AgMjUwIGdhbWVzIG9mIGVhY2ggZ2VucmUgYW5kIHBvcHVsYXJpdHkuIEJlY2F1c2UgU3RlYW0gaXMgc3VjaCBhIGxhcmdlIHBsYXRmb3JtIHRoZSBtb3N0IGNvbW1vbiBhc3BlY3Qgb2YgYSBnZW5yZSBpcyBub3QgbmVjY2VzYXJpbHkgdGhlIG1vc3Qgc3VjY2Vzc2Z1bCBhcyBzaG93biBieSB0aGUgcGxheWVyIGNvdW50IGJhciBncmFwaC4NCg0KYGBge3J9DQojTm93IGRvIHRoZSBzYW1lIHN0ZXBzIGZyb20gZmluZGluZyB0aGUgVG9wXzI1MF9HYW1lcyB0byBmaW5kIHRoZSAyNTAgbW9zdCBwb3B1bGFyIGdhbWVzIHdpdGhpbiB0aGUgc2ltdWxhdGlvbiBnZW5yZQ0KDQojTWFrZSBhIHN1YnNldDoNCg0KI1N1YnNldCBvZiBzaW11bGF0aW9uIGdhbWVzDQpTaW1fR2FtZXMgPC0gU3RlYW1fR2FtZXNbZ3JlcGwoIlNpbXVsYXRpb24iLCBTdGVhbV9HYW1lcyRHZW5yZXMpLCBdDQoNCg0KI0ZpbmQgdGhlIHRvcCAyNTAgZnJvbSBzaW0gZ2FtZXMgDQoNClRvcF8yNTBfU2ltcyA8LSBTaW1fR2FtZXMgJT4lDQogIGFycmFuZ2UoZGVzYyhPd25lcnMuYXZnKSkgJT4lDQogIA0KICBoZWFkKDI1MCkNCg0KVG9wXzI1MF9TaW1zDQpUb3BfMjUwX0dhbWVzDQpgYGANCg0KIyMjIFBsYXllcnNoaXANCg0KIyMjIyBHcm91cGVkIEJhciBjaGFydCB0byBjb21wYXJlIHBsYXllciBiYXNlcw0KDQpgYGB7cn0NCiMgTm93IHRoYXQgd2UgaGF2ZSBvdXIgYnJvYWQgc2V0cywgQ3JlYXRlIGEgZ3JvdXBlZCBiYXIgY2hhcnQgdG8gY29tcGFyZSBwbGF5ZXIgYmFzZXMNCg0KIyBTZWxlY3QgQ29sdW1ucyBTZXRzIHRvIGluY2x1ZGUgbWF4IG93bmVycyBhbmQgTmFtZQ0KVG9wXzI1MF9HYW1lc19NTyA8LSBUb3BfMjUwX0dhbWVzICU+JQ0KICBzZWxlY3QoT3duZXJzLmF2ZywgTmFtZSkNClRvcF8yNTBfU2ltc19NTyA8LSBUb3BfMjUwX1NpbXMgJT4lDQogIHNlbGVjdChPd25lcnMuYXZnLCBOYW1lKQ0KDQojIENvbnZlcnQgZGF0YSB0byBiZSBpbiB0aGUgc2FtZSBzZXQNClRvcF8yNTBfR2FtZXNfTU8kU291cmNlIDwtICJHZW5lcmFsIg0KVG9wXzI1MF9TaW1zX01PJFNvdXJjZSA8LSAiU2ltdWxhdGlvbnMiDQoNClRvcF9Db21wYXJlXzI1MCA8LSByYmluZChUb3BfMjUwX0dhbWVzX01PLCBUb3BfMjUwX1NpbXNfTU8pICNyYmluZCB0YWtlcyB0aGUgdHdvIGNvbHVtbnMgYW5kIG1ha2VzIHRoZSB0d28gb25lDQoNCiMgU3VtbWFyaXplIHRoZSBkYXRhIHRvIGdldCB0aGUgY291bnRzDQpzdW1tYXJ5X2RhdGEgPC0gVG9wX0NvbXBhcmVfMjUwICU+JQ0KICBncm91cF9ieShTb3VyY2UpICU+JQ0KICBzdW1tYXJpc2UoQ291bnQgPSBuKCkpICMgbigpIGNvdW50cyB0aGUgbnVtYmVyIG9mIHJvd3MgaW4gZWFjaCBncm91cA0KDQojIENyZWF0ZSBCaW5zDQpUb3BfQ29tcGFyZV8yNTAkT3duZXJfQmlucyA8LSBjdXQoVG9wX0NvbXBhcmVfMjUwJE93bmVycy5hdmcsIGJyZWFrcyA9IDIwKQ0KDQojIDIuIFBsb3QgdGhlIGRhdGEgdXNpbmcgdGhlIG5ldyBiaW5zDQpnZ3Bsb3QoVG9wX0NvbXBhcmVfMjUwLCBhZXMoeCA9IE93bmVyX0JpbnMsIGZpbGwgPSBTb3VyY2UpKSArDQogIGdlb21fYmFyKHBvc2l0aW9uID0gImRvZGdlIiwgY29sb3IgPSAiY2FkZXRibHVlNCIpICsNCiAgbGFicygNCiAgICB0aXRsZSA9ICJTaW11bGF0aW9uIGFuZCBUb3AgMjUwIEdhbWVzIENvbXBhcmlzb24gYnkgRXN0aW1hdGVkIE93bmVycyIsDQogICAgeCA9ICJFc3RpbWF0ZWQgT3duZXJzIiwNCiAgICB5ID0gIkNvdW50IG9mIEdhbWVzIiwNCiAgICBmaWxsID0gIkRhdGEgU291cmNlIg0KICApICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgaGp1c3QgPSAxLCB2anVzdCA9IDAuNSkpICsNCg0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJjYWRldGJsdWUzIiwgImRhcmtncmV5IikpDQoNCmBgYA0KDQojIyMjIyBHcmFwaCBEZXNjcmlwdGlvbjoNCg0KVGhlIGFib3ZlIGdyYXBoIHNob3dzIHRoYXQsIHdoZW4gY29tcGFyZWQgdG8gdGhlIHRvcCAyNTAgZ2FtZXMgb24gc3RlYW0sIG1vcmUgc2ltdWxhdGlvbiBnYW1lcyBhcmUsIFRoZSB3aWRlciBiYXJzIGFsc28gc2hvdyBhbiBpbnRlcmVzdGluZyBhc3BlY3Qgb2YgdGhlIHNpbXVsYXRpb24gZ2VucmUgYXMgYSB3aG9sZS5JdCBzaG93cyB0aGF0IG1vc3Qgb2YgdGhlIHRvcCAyNTAgZ2FtZXMgb2YgdGhlIHNpbXVsYXRpb24gZ2VucmUgZG9uJ3QgcmVhY2ggdGhlIHNhbWUgcGxheWVyIGNvdW50cyBhcyB0aGUgYWN0aW9uIGdlbnJlIG1pZ2h0LiBBZGRpdGlvbmFsbHkgdGhlIGdyYXBoIHNob3dzIHRoYXQgYSBmZXcgZ2FtZXMgc2l0IGF0IHRoZSB0b3Agb2YgU3RlYW0ncyByb3N0ZXIuDQoNCiMjIyMgU2NhdHRlciBQbG90IC0gUGxheWVyIEVuZ2FnZW1lbnQgYW5kIEdhbWUgT3duZXJzaGlwDQoNClZpc3VhbGl6YXRpb24gb2YgcHJldmlvdXMgY29ycmVsYXRpb24gYW5hbHlzaXMgYmV0d2VlbiBwbGF5ZXIgZW5nYWdlbWVudCBhbmQgZXN0aW1hdGVkIG93bmVyc2hpcA0KDQpgYGB7cn0NCiMgY3JlYXRlIHBlcmNlbnQgcG9zaXRpdmUgcmV2aWV3cw0KVG9wXzI1MF9HYW1lcyA8LSBUb3BfMjUwX0dhbWVzICU+JQ0KICBtdXRhdGUoUG9zaXRpdmVfUEUgPSAoUG9zaXRpdmUgLyAoUG9zaXRpdmUgKyBOZWdhdGl2ZSkpKQ0KDQpgYGANCg0KYGBge3J9DQojIE1ha2luZyB0aGUgc2NhdHRlciBwbG90IHdpdGggYSBsb2ctdHJhbnNmb3JtZWQgWC1heGlzDQoNCmdncGxvdChkYXRhID0gVG9wXzI1MF9HYW1lcywgYWVzKHggPSBPd25lcnMuYXZnLCB5ID0gUG9zaXRpdmVfUEUpKSArDQogIGdlb21fcG9pbnQoY29sb3IgPSAiZ3JleTIiLCBhbHBoYSA9IDAuMDUsIHNpemUgPSAyKSArDQogICMgQWRkIHRoZSBsaW5lYXIgdHJlbmRsaW5lIHVzaW5nIGdlb21fc21vb3RoKCkNCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2UgPSBGQUxTRSwgY29sb3IgPSAiY2FkZXRibHVlNCIpICsNCiAgc2NhbGVfeF9sb2cxMCgpICsNCiAgbGFicyh0aXRsZSA9ICJUb3AgMjUwIEdhbWVzIFBvc2l0aXZlIFJhdGluZ3MgJSIsDQogICAgICAgeCA9ICJFc3RpbWF0ZWQgT3duZXJzIChMb2cgU2NhbGUpIiwNCiAgICAgICB5ID0gIlBlcmNlbnQgUG9zaXRpdmUiKSArDQogIHRoZW1lX21pbmltYWwoKQ0KYGBgDQoNCiMjIyMjIEdyYXBoIERlc2NyaXB0aW9uDQoNClRoZSBhYm92ZSBncmFwaCBzaG93cyB0aGUgcGVyY2VudCBvZiBwb3NpdGl2ZSByYXRpbmcgZ2l2ZW4gZm9yIGEgZ2FtZSBhbmQgdGhlIGVzdGltYXRlZCBvd25lcnMgZm9yIHRoYXQgZ2FtZS4gVGhlIGdhbWVzIGluIHRoaXMgcGxvdCBhcmUgYXBhcnQgb2YgdGhlIHRvcCAyNTAgZ2FtZXMgb24gU3RlYW0uIEdhbWVzIHRlbmQgdG8gaGF2ZSBhIHBlcmNlbnQgcG9zaXRpdmUgcmF0aW5nIG9mIGFyb3VuZCA4NSUgd2l0aCB0aGUgcGVyY2VudGFnZSBzbGlnaHRseSBkZWNyZWFzaW5nIGFzIHRoZXJlIGFyZSBsZXNzIGdhbWVzIGRvd24gdGhlIGxpbmUuDQoNCiMjIyMgU2NhdHRlciBQbG90IFJlcHJlc2VudGluZyBSZXZpZXdzIGFuZCBPd25lcnNoaXANCg0KYGBge3J9DQojTXV0YXRlIHdob2xlIGRhdGFzZXQNClN0ZWFtX0dhbWVzIDwtIFN0ZWFtX0dhbWVzICU+JQ0KICBtdXRhdGUoUG9zaXRpdmVfUEUgPSAoUG9zaXRpdmUgLyAoUG9zaXRpdmUgKyBOZWdhdGl2ZSkpKQ0KYGBgDQoNCmBgYHtyfQ0KDQojIE1ha2luZyB0aGUgc2NhdHRlciBwbG90IHdpdGggYSBsb2ctdHJhbnNmb3JtZWQgWC1heGlzDQoNCmdncGxvdChkYXRhID0gU3RlYW1fR2FtZXMsIGFlcyh4ID0gT3duZXJzLmF2ZywgeSA9IFBvc2l0aXZlX1BFKSkgKw0KICBnZW9tX3BvaW50KGNvbG9yID0gIm1lZGl1bXNlYWdyZWVuIiwgYWxwaGEgPSAwLjA1LCBzaXplID0gMikgKw0KICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBzZSA9IEZBTFNFLCBjb2xvciA9ICJkYXJrZ3JlZW4iKSArICMgQWRkcyBhIGxpbmVhciB0cmVuZGxpbmUNCiAgc2NhbGVfeF9sb2cxMCgpICsNCiAgbGFicyh0aXRsZSA9ICJHYW1lcyBQb3NpdGl2ZSBSYXRpbmdzICUgIiwNCiAgICAgICB4ID0gIkVzdGltYXRlZCBPd25lcnMgKExvZyBTY2FsZSkiLA0KICAgICAgIHkgPSAiUGVyY2VudCBQb3NpdGl2ZSBSYXRpbyIpICsNCiAgdGhlbWVfbWluaW1hbCgpDQpgYGANCg0KIyMjIyMgR3JhcGggZGVzY3JpcHRpb24NCg0KVGhpcyBncmFwaCBzaG93cyBhIHNpbWlsYXIgdHJlbmQgdG8gdGhlIHByZXZpb3VzIGdyYXBoIGJ1dCBpbnN0ZWFkLCBpdCBzaG93cyBhIHNsaWdodCBpbmNyZWFzZSBmcm9tIDc1JS4gQWRkaXRpb25hbGx5LCBhcyB0aGUgbnVtYmVyIG9mIG93bmVycyBpbmNyZWFzZXMgdGhlIHZhcmlldHkgb2YgcmF0aW5ncyBiZWNvbWVzIG1vcmUgc3RhbmRhcmQuIFRoaXMgZGF0YSBpcyBzb3VyY2VkIGZyb20gdGhlIHdob2xlIGRhdGEgc2V0IHJhdGhlciB0aGFuIGEgc3Vic2V0IGxpa2UgdGhlIHByZXZpb3VzIHNldC4NCg0KIyMjIEZpbmRpbmcgdGhlIE1vc3QgUG9wdWxhciBHZW5yZQ0KDQpgYGB7cn0NCiNGaW5kaW5nIHdoYXQgcGVyY2VudCBvZiB0b3AgMjUwIGdhbWVzIGNvbnRhaW4gYWN0aW9uIGluIHRoZWlyIGdlbnJlcyBjb2x1bW4gKHRoZXJlIGFyZSAyNTAgcm93cyBpbiB0aGlzIHNldCkNCg0KI0luIFRvcF9HYW1lc18yNTAgdXNlIGdyZXBsIHRvIGZpbmQgYWxsIGdhbWVzIHdpdGggdGhlbiBzYXZlIHRvIEFjdGlvbl9HYW1lc19mcm9tXzI1MA0KQWN0aW9uX0dhbWVzX2Zyb21fMjUwIDwtIFRvcF8yNTBfR2FtZXNbZ3JlcGwoIkFjdGlvbiIsIFRvcF8yNTBfR2FtZXMkR2VucmVzKSwgXQ0KDQojIEZpbmQgcGVyY2VudA0KUGVyY2VudF9BY3Rpb24gPSAobnJvdyhBY3Rpb25fR2FtZXNfZnJvbV8yNTApLzI1MCkqMTAwDQpQZXJjZW50X0FjdGlvbg0KYGBgDQoNCiMjIyMjIENvZGUgRGVzY3JpcHRpb246DQoNCkJhc2VkIG9uIHRoZSBBYm92ZSBjb2RlLCBnYW1lcyB0aGF0IHVzZSB0aGUgYWN0aW9uIHRhZyBtYWtlIHVwIDcwLjglIG9mIHRoZSB0b3AgMjUwIGdhbWVzLiBUaGUgZGF0YSBzZXQgd2FzIHJhbmtlZCBieSBlc3RpbWF0ZWQgb3duZXJzaGlwIG1lYW5pbmcsIG9mIHRoZSBtb3N0IHBvcHVsYXIgZ2FtZXMgNzAuOCUgb2YgdGhlbSBmYWxsIHVuZGVyIHRoZSBhY3Rpb24gZ2VucmUsIG1ha2luZyBhY3Rpb24gZ2FtZXMgdGhlIG1vc3QgcG9wdWxhciBnZW5yZSBvbiBTdGVhbSBieSBvd25lcnNoaXAuDQoNCiMjIyMgRmluZGluZyBhY3Rpb24gZ2FtZXMgZ2VucmUgdG9wIDI1MA0KDQpgYGB7cn0NCiNGb3IgdGhlIG5leHQgYml0IG9mIGNvZGUgaW52b2x2aW5nIHBpZSBjaGFydHMsIEkgYW0gZmluZGluZyB0aGUgdG9wIDI1MCBhY3Rpb24gZ2FtZXMgc28gSSBtYXkgY29tcGFyZSBhIHZlcnkgc3VjY2Vzc2Z1bCBnZW5yZSB0byB0aGUgc2ltdWxhdGlvbiBnZW5yZS4NCg0KVG9wXzI1MF9BY3Rpb24gPC0gU3RlYW1fR2FtZXMgJT4lDQogIGZpbHRlcihncmVwbCgiQWN0aW9uIiwgR2VucmVzKSkgJT4lDQogIGFycmFuZ2UoZGVzYyhPd25lcnMuYXZnKSkgJT4lDQogIGhlYWQoMjUwKQ0KDQojIFByaW50IHRoZSByZXN1bHQNClRvcF8yNTBfQWN0aW9uDQoNCmBgYA0KDQojIyMjIyBDb2RlIEV4cGxhbmF0aW9uOg0KDQpOYXJyb3dpbmcgbXkgc2NvcGUgSSBkZWNpZGVkIHRvIHB1bGwgdGhlIHRvcCAyNTAgYWN0aW9uIGdhbWVzIGZyb20gdGhlIFN0ZWFtIExpYnJhcnkgc28gSSBtYXkgY29tcGFyZSB0aGUgc2ltdWxhdGlvbiBnZW5yZSBhZ2FpbnN0IHRoZSBtb3N0IHBvcHVsYXIgZ2VucmUuIEp1c3QgYXMgd2l0aCB0aGUgU2ltdWxhdGlvbiBnZW5yZSwgZ2FtZXMgb24gc3RlYW0gYXJlIGFsbG93ZWQgbW9yZSB0aGFuIG9uZSBnZW5yZSB0YWcgbWVhbmluZyBpZiBhIGdhbWUgaXMgdGFnZ2VkIHdpdGggYm90aCB0aGUgYWN0aW9uIGFuZCBzaW11bGF0aW9uIHRhZywgdGhlIGdhbWUgd2lsbCBiZSBjb250YWluZWQgaW4gYm90aCBzZXRzLg0KDQojIyMgR3JhcGg6IFByaWNlIFBpZSBDaGFydHMNCg0KYGBge3J9DQojIDEuIERlZmluZSB0aGUgZGF0YSAobnVtZXJpYyB2ZWN0b3Igb2YgY291bnRzKQ0KICNJbiBUb3BfR2FtZXNfMjUwIHVzZSBncmVwbCB0byBmaW5kIGFsbCBnYW1lcyB3aXRoIHRoZW4gc2F2ZSB0byBBY3Rpb25fR2FtZXNfZnJvbV8yNTANCkYyUF9HYW1lc19mcm9tXzI1MCA8LSBUb3BfMjUwX0dhbWVzW2dyZXBsKCJGcmVlIHRvIFBsYXkiLCBUb3BfMjUwX0dhbWVzJEdlbnJlcyksIF0NCg0KIyAyLiBGaW5kIHBlcmNlbnRhZ2VzDQpQZXJjZW50X0YyUCA9IHJvdW5kKCgobnJvdyhGMlBfR2FtZXNfZnJvbV8yNTApLzI1MCkqMTAwKSwyKQ0KTm90X0ZyZWUgPSAtUGVyY2VudF9GMlAgKyAxMDANCg0KIyAzLiBNYWtpbmcgdGhlIGNvdW50cyB2YXJpYWJsZQ0KY291bnRzIDwtIGMoUGVyY2VudF9GMlAsIE5vdF9GcmVlKQ0KDQojIDIuIERlZmluZSB0aGUgbGFiZWxzIGZvciB0aGUgc2xpY2VzIChjaGFyYWN0ZXIgdmVjdG9yKQ0KbGFiZWxzIDwtIGMoIkZyZWUgdG8gUGxheSIsICJOb3QgRnJlZSB0byBQbGF5IikNCg0KIyAzLiBEZWZpbmUgdGhlIGNvbG9ycw0KY29sb3JzIDwtIGMoImdyYXkiLCAiZGFya2dyYXkiKQ0KDQojIDQuIEdlbmVyYXRlIHRoZSBwaWUgY2hhcnQgdXNpbmcgdGhlICdwaWUoKScgZnVuY3Rpb24NCkYyUF9QaWVfMjUwIDwtIHBpZSgNCiAgeCA9IGNvdW50cywgICAgICAgICAjIFRoZSBudW1lcmljIHZhbHVlcw0KICBsYWJlbHMgPSBsYWJlbHMsICAgICMgVGhlIHRleHQgbGFiZWxzIGZvciBlYWNoIHNsaWNlDQogIG1haW4gPSAiUGVyY2VudCBGcmVlIHRvIFBsYXkgKFRvcCAyNTApIiwgIyBNYWluIHRpdGxlICAgICAgIA0KICBjb2wgPSBjb2xvcnMgIyBDb2xvcnMgZm9yIHRoZSBzbGljZXMNCikgDQoNCiNNYWtlIFNpbSBGcmVlIHRvIHBsYXkgcGllIGNoYXJ0DQoNCiMgMS4gRGVmaW5lIHRoZSBkYXRhIChudW1lcmljIHZlY3RvciBvZiBjb3VudHMpDQogI0luIFRvcF9HYW1lc18yNTAgdXNlIGdyZXBsIHRvIGZpbmQgYWxsIGdhbWVzIHdpdGggdGhlbiBzYXZlIHRvIEFjdGlvbl9HYW1lc19mcm9tXzI1MA0KRjJQX0dhbWVzX2Zyb21fU2ltIDwtIFRvcF8yNTBfU2ltc1tncmVwbCgiRnJlZSB0byBQbGF5IiwgVG9wXzI1MF9TaW1zJEdlbnJlcyksIF0NCg0KIyAyLiBGaW5kIHBlcmNlbnRhZ2VzDQpQZXJjZW50X0YyUDIgPSByb3VuZCgoKG5yb3coRjJQX0dhbWVzX2Zyb21fU2ltKS8yNTApKjEwMCksMikNCk5vdF9GcmVlMiA9IC1QZXJjZW50X0YyUDIgKyAxMDANCg0KIyAzLiBNYWtpbmcgdGhlIGNvdW50cyB2YXJpYWJsZQ0KY291bnRzIDwtIGMoUGVyY2VudF9GMlAyLCBOb3RfRnJlZTIpDQoNCiMgMi4gRGVmaW5lIHRoZSBsYWJlbHMgZm9yIHRoZSBzbGljZXMgKGNoYXJhY3RlciB2ZWN0b3IpDQpsYWJlbHMgPC0gYygiRnJlZSB0byBQbGF5IiwgIk5vdCBGcmVlIHRvIFBsYXkiKQ0KDQojIDMuIERlZmluZSB0aGUgY29sb3JzDQpjb2xvcnMgPC0gYygiY2FkZXRibHVlMyIsICJjYWRldGJsdWUiKQ0KDQojIDQuIEdlbmVyYXRlIHRoZSBwaWUgY2hhcnQgdXNpbmcgdGhlICdwaWUoKScgZnVuY3Rpb24NCkYyUF9QaWVfU2ltcyA8LSBwaWUoDQogIHggPSBjb3VudHMsICAgICAgICAgIyBUaGUgbnVtZXJpYyB2YWx1ZXMNCiAgbGFiZWxzID0gbGFiZWxzLCAgICAjIFRoZSB0ZXh0IGxhYmVscyBmb3IgZWFjaCBzbGljZQ0KICBtYWluID0gIlBlcmNlbnQgRnJlZSB0byBQbGF5IChUb3AgU2ltcykiLCAjIE1haW4gdGl0bGUgICAgICAgDQogIGNvbCA9IGNvbG9ycyAjIENvbG9ycyBmb3IgdGhlIHNsaWNlcw0KKSANCg0KRjJQX1BpZV8yNTANCg0KRjJQX1BpZV9TaW1zDQoNCiNNYWtlIEFjdGlvbiBGcmVlIHRvIHBsYXkgcGllIGNoYXJ0DQoNCiMgMS4gRGVmaW5lIHRoZSBkYXRhIChudW1lcmljIHZlY3RvciBvZiBjb3VudHMpDQogI0luIFRvcF9HYW1lc18yNTAgdXNlIGdyZXBsIHRvIGZpbmQgYWxsIGdhbWVzIHdpdGggdGhlbiBzYXZlIHRvIEFjdGlvbl9HYW1lc19mcm9tXzI1MA0KRjJQX0dhbWVzX2Zyb21fQWN0aW9uIDwtIFRvcF8yNTBfQWN0aW9uW2dyZXBsKCJGcmVlIHRvIFBsYXkiLCBUb3BfMjUwX0FjdGlvbiRHZW5yZXMpLCBdDQoNCiMgMi4gRmluZCBwZXJjZW50YWdlcw0KUGVyY2VudF9GMlAzID0gcm91bmQoKChucm93KEYyUF9HYW1lc19mcm9tX0FjdGlvbikvMjUwKSoxMDApLDIpDQpOb3RfRnJlZTMgPSAtUGVyY2VudF9GMlAzICsgMTAwDQoNCiMgMy4gTWFraW5nIHRoZSBjb3VudHMgdmFyaWFibGUNCmNvdW50cyA8LSBjKFBlcmNlbnRfRjJQMywgTm90X0ZyZWUzKQ0KDQojIDIuIERlZmluZSB0aGUgbGFiZWxzIGZvciB0aGUgc2xpY2VzIChjaGFyYWN0ZXIgdmVjdG9yKQ0KbGFiZWxzIDwtIGMoIkZyZWUgdG8gUGxheSIsICJOb3QgRnJlZSB0byBQbGF5IikNCg0KIyAzLiBEZWZpbmUgdGhlIGNvbG9ycw0KY29sb3JzIDwtIGMoIm1lZGl1bXNlYWdyZWVuIiwgImRhcmtncmVlbiIpDQoNCiMgNC4gR2VuZXJhdGUgdGhlIHBpZSBjaGFydCB1c2luZyB0aGUgJ3BpZSgpJyBmdW5jdGlvbg0KRjJQX1BpZV9BY3Rpb24gPC0gcGllKA0KICB4ID0gY291bnRzLCAgICAgICAgICMgVGhlIG51bWVyaWMgdmFsdWVzDQogIGxhYmVscyA9IGxhYmVscywgICAgIyBUaGUgdGV4dCBsYWJlbHMgZm9yIGVhY2ggc2xpY2UNCiAgbWFpbiA9ICJQZXJjZW50IEZyZWUgdG8gUGxheSAoVG9wIEFjdGlvbikiLCAjIE1haW4gdGl0bGUgICAgICAgDQogIGNvbCA9IGNvbG9ycyAjIENvbG9ycyBmb3IgdGhlIHNsaWNlcw0KKSANCg0KRjJQX1BpZV8yNTANCg0KRjJQX1BpZV9TaW1zDQoNCkYyUF9QaWVfQWN0aW9uDQpgYGANCg0KIyMjIyMgR3JhcGggRGVzY3JpcHRpb25zOg0KDQpEZXNwaXRlIGxvd2VyIHByaWNlZCBnYW1lcyBiZWluZyBtb3JlIGFjY2Vzc2libGUsIHRoZSBtYWpvcml0eSBvZiBnYW1lcyBpbiBlYWNoIHJlc3BlY3RpdmUgY2F0YWdvcnkgYXJlIHJvdWdobHkgNCB0aW1lcyBtb3JlIGxpa2VseSB0byBub3QgYmUgZnJlZSB0byBwbGF5LiBTaW11bGF0aW9uIGdhbWVzIGFyZSB0aGUgbGVhc3QgbGlrZWx5IHRvIGJlIGZyZWUgdG8gcGxheS4NCg0KIyMjIyMjIEV4YWN0IFBlcmNlbnRzIGZvciBhYm92ZSBncmFwaA0KDQpgYGB7cn0NCnByaW50KCJQZXJjZW50IEZyZWUgKDI1MCwgU2ltLCBBY3Rpb24pICIpDQoNClBlcmNlbnRfRjJQDQpQZXJjZW50X0YyUDINClBlcmNlbnRfRjJQMw0KDQpwcmludCgiUGVyY2VudCBOb3QgRnJlZSAoMjUwLCBTaW0sIEFjdGlvbikgIikNCg0KTm90X0ZyZWUNCk5vdF9GcmVlMg0KTm90X0ZyZWUzDQpgYGANCg0KIyMjIyMjIENvZGUgRGVzY3JpcHRpb24NCg0KVGhlIGFib3ZlIGNvZGUgc2hvd3MgdGhlIGV4YWN0IHBlcmNlbnRhZ2VzIGZvciBlYWNoIG9mIHRoZSBwaWUgY2hhcnRzLg0KDQojIyMgUHJpY2UgQ29tcGFyaXNvbg0KDQpgYGB7cn0NCnByaWNlX2RmIDwtIGRhdGEuZnJhbWUoDQogIEdhbWVzX1ByaWNlID0gVG9wXzI1MF9HYW1lcyRQcmljZSwNCiAgU2ltc19QcmljZSA9IFRvcF8yNTBfU2ltcyRQcmljZSwNCiAgQWN0aW9uX1ByaWNlID0gVG9wXzI1MF9BY3Rpb24kUHJpY2UNCikNCg0Kc3VtbWFyeShwcmljZV9kZikNCg0KYGBgDQoNCiMjIyMjIENvZGUgRXhwbGFuYXRpb246DQoNClRoaXMgY29kZSBwcm92aWRlcyBudW1lcmljYWwgaW5mb3JtYXRpb24gYWJvdXQgdGhlIHByaWNlIG9mIGVhY2ggdmFyaWFibGUuDQoNCiMjIyMgUHJpY2UgQm94IGFuZCBXaGlza2VyIFBsb3QNCg0KYGBge3J9DQojIENvbnZlcnQgdGhlIGRhdGEgZnJhbWUgdG8gYSBsb25nIGZvcm1hdA0KcHJpY2VfbG9uZyA8LSBwaXZvdF9sb25nZXIocHJpY2VfZGYsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbHMgPSBjKEdhbWVzX1ByaWNlLCBTaW1zX1ByaWNlLCBBY3Rpb25fUHJpY2UpLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYW1lc190byA9ICJHYW1lX1R5cGUiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZXNfdG8gPSAiUHJpY2UiKQ0KDQojIENyZWF0ZSB0aGUgYm94IGFuZCB3aGlza2VyIHBsb3QgdXNpbmcgZ2dwbG90Mg0KZ2dwbG90KHByaWNlX2xvbmcsIGFlcyh4ID0gR2FtZV9UeXBlLCB5ID0gUHJpY2UsIGZpbGwgPSBHYW1lX1R5cGUpKSArDQogIGdlb21fYm94cGxvdCgpICsNCiAgbGFicyh0aXRsZSA9ICJQcmljZSBEaXN0cmlidXRpb24gQWNyb3NzIEdhbWUgVHlwZXMiLA0KICAgICAgIHkgPSAiUHJpY2UiLA0KICAgICAgIHggPSAiR2FtZSBUeXBlIikgKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJtZWRpdW1zZWFncmVlbiIsICJncmV5IiwgImNhZGV0Ymx1ZTMiKSkgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICBzdGF0X3N1bW1hcnkoZnVuID0gIm1lZGlhbiIsIA0KICAgICAgICAgICAgICAgZ2VvbSA9ICJ0ZXh0IiwgDQogICAgICAgICAgICAgICBhZXMobGFiZWwgPSByb3VuZChhZnRlcl9zdGF0KHkpLCAyKSksICMgUm91bmRzIHRoZSBtZWRpYW4gdmFsdWUgKDIgZGVjaW1hbHMgZm9yIGN1cnJlbmN5KQ0KICAgICAgICAgICAgICAgdmp1c3QgPSAtMC41LCAjIEFkanVzdHMgdmVydGljYWwgcG9zaXRpb24gdG8gYmUgc2xpZ2h0bHkgYWJvdmUgdGhlIG1lZGlhbiBsaW5lDQogICAgICAgICAgICAgICBjb2xvciA9ICJ3aGl0ZSIpDQpgYGANCg0KIyMjIyMgR3JhcGggRGVzY3JpcHRpb246DQoNClRoZSBncmFwaCBzaG93cyB0aGF0IHNpbXVsYXRpb24gZ2FtZXMgdGVuZCB0byBiZSBwcmljZWQgaGlnaGVyIHRoYW4gb3RoZXIgcG9wdWxhciBnYW1lcy4gSG93ZXZlciwgdGhlIG1vc3QgZXhwZW5zaXZlIGdhbWVzIGFyZSBmbG9hdGluZyBhcm91bmQgdGhlIG1vc3QgcG9wdWxhciBnYW1lcy4NCg0KYGBge3J9DQoNCiMgSSBmb3VuZCBpdCBpbnRlcmVzdGluZyB0aGF0IHRoZSBhY3Rpb24gYW5kIHRvcCBnYW1lcyBoYWQgYSBkaWZmZXJlbnQgbWF4IHByaWNlIGJ5IHN1Y2ggYSBsYXJnZSBtYXJnaW4gYW5kIHNvIEkgd2FudGVkIHRvIHNlZSB3aGF0IGdhbWVzIGNvc3QgdGhlIG1vc3QgaW4gdGhlIHRvcCAyNTAuDQoNCk1vc3RfRXhwZW5zaXZlXzI1MCA8LSBUb3BfMjUwX0dhbWVzW1RvcF8yNTBfR2FtZXMkUHJpY2UgPT0gbWF4KHByaWNlX2RmJEdhbWVzX1ByaWNlKSwgXQ0KDQpwcmludChNb3N0X0V4cGVuc2l2ZV8yNTApDQoNCmBgYA0KDQojIyMjIyBDb2RlIEV4cGxhbmF0aW9uOg0KDQonU3RhcmZpZWxkJyBpcyBhIGdhbWUgYnkgYSBtYWpvciBzdHVkaW8sIEJldGhlc2RhLCBhbmQgaXMgYW4gb3BlbiB3b3JsZCBzcGFjZSBzaW11bGF0aW9uIHdpdGggcmVhbGlzdGljIGdyYXBoaWNzIHRoYXQgdG9vayBhcm91bmQgNyB5ZWFycyB0byBkZXZlbG9wLg0KDQojIFJlc3VsdHMNCg0KIyMgRGVzY3JpcHRpb24gb2YgQW5hbHlzaXMNCg0KUmVnYXJkaW5nIHRoZSBmaXJzdCBtYWluIHF1ZXN0aW9uLCB0aGUgZmlyc3QgUCBvZiB0aGUgNFDigJlzIGlzIHBsYWNlLiBJbiB0aGlzIGNhc2UsIHRoZSBwbGFjZSBpcyBTdGVhbS4gVGhlIGFuYWx5c2lzIHdpbGwgYmVnaW4gYnkgbG9va2luZyBhdCB0aGUgZGlzdHJpYnV0aW9uIG9mIGdlbnJlIHRhZ3MgYW1vbmcgYWxsIGdhbWVzIG9uIFN0ZWFtIHRoZW4gY291bnRpbmcgZ2FtZXMgYnkgdGhlaXIgb3duZXJzaGlwLiBFc3RpbWF0ZWQgb3duZXJzaGlwIGlzIHRoZSBiZXN0IG1ldHJpYyBmb3Igc3VjY2VzcyBpbiBteSBkYXRhIHNldCBhcyB0aGVyZSBpcyBubyBzZXQgcXVhbGl0eSB2YWx1ZSBhcyBpdCBpcyBhIHZlcnkgY29tcGxleCBzdWJqZWN0LiBVc2luZyB0aGlzIHZhcmlhYmxlLCBJIGRlY2lkZWQgdG8gdXNlIGl0IHRvIGxvb2sgaW50byB0aGUgc2Vjb25kIFAsIHByb2R1Y3QuIEluIHRoaXMgY2FzZSwgdGhlIHByb2R1Y3QgaXMgdGhlIGdlbnJlIGJlY2F1c2UgZ2VucmVzIHRlbmQgdG8gaGF2ZSBzaW1pbGFyaXRpZXMgYW5kIGRpZmZlcmVudCB0YXJnZXQgYXVkaWVuY2VzIG1ha2luZyBpdCBhIGdvb2QgbWVhc3VyZSBmb3Igc2VwYXJhdGluZyBvbmUgcHJvZHVjdCBmcm9tIGFub3RoZXIuIEZvciB0aGlzIHF1ZXN0aW9uLCBhIGNvbXBhcmlzb24gb2YgdGhlIGVzdGltYXRlZCBvd25lcnMgd2lsbCBiZSBjb21wbGV0ZWQuDQoNClRoZSB0aGlyZCBQLCBwcmljZSwgd2FzIGFuIGludGVyZXN0aW5nIGFzcGVjdC4gRmlyc3QsIHRoZSBwZXJjZW50YWdlIG9mIGZyZWUgdG8gcGxheSBnYW1lcyBhbW9uZyB0aGUgdG9wIDI1MCwgdG9wIHNpbXVsYXRpb24gZ2FtZXMsIGFuZCB0b3AgYWN0aW9uIGdhbWVzIHdpbGwgYmUgY29tcGFyZWQgdG8gZWFjaCBvdGhlciB0byBkZWNpZGUgaWYgdGhlIGRldmVsb3BlciBpbiB0aGUgc2ltdWxhdGlvbiBnZW5yZSBjb3VsZCBleHBlY3QgdGhhdCBmcmVlIHRvIHBsYXkgZ2FtZXMgaW4gdGhlIFNpbXMgZ2VucmUgd2lsbCBwZXJmb3JtIGJldHRlci4gQWZ0ZXIgdGhpcywgdGhlIHByaWNlcyBmb3IgZWFjaCBnYW1lIHR5cGUgd2lsbCBiZSBhbmFseXplZCB0aHJvdWdoIHRoZSB1c2Ugb2YgYSBib3ggYW5kIHdoaXNrZXIgcGxvdC4gRGVzcGl0ZSB0aGUgZm91cnRoIFAsIHByb21vdGlvbiBiZWluZyBJbXBvcnRhbnQsIGl0IHdhcyBkZWNpZGVkIHRoYXQgdGhlIGZvdXJ0aCBQIHdpbGwgbm90IGJlIGNvdmVyZWQgYXMgZGlyZWN0bHkgYXMgdGhlIG90aGVyIHRocmVlIGFzcGVjdHMuIEZ1bmRzIHNwZW50IG9uIHByb21vdGlvbiBpcyBub3QgYW4gYXZhaWxhYmxlIHZhbHVlIHdpdGggdGhpcyBkYXRhc2V0LCBpbnN0ZWFkIHRoZSBvdGhlciAzIHdpbGwgYmUgdGhlIGZvY3VzIGFuZCB0aGlzIGFzcGVjdCBtYXkgYmUgY29uc2lkZXJlZCBtb3JlIGhvbGlzdGljYWxseSB3aXRoIHRoZSBhc3N1bXB0aW9uIHRoYXQgZ2FtZSBvd25lcnNoaXAgaW4gaXRzZWxmIGlzIGEgZm9ybSBvZiBwcm9tb3Rpb24uDQoNCiMjIFJlYXNvbnNpbmcgYmVoaW5kIG1ldGhvZHMgb2YgY2hvaWNlDQoNClRoZSB0eXBlIG9mIGRhdGEgYW5hbHlzaXMgdGhhdCB3YXMgY2hvc2VuIHRvIGJlIHRoZSBmb2N1cyBpcyBiaXZhcmlhdGUuIFRoaXMgbWV0aG9kIHdhcyBjaG9zZW4gYmVjYXVzZSBtb3N0IG9mIHRoZSBhbmFseXNpcyBzdXJyb3VuZHMgY29tcGFyaXNvbiBiZXR3ZWVuIHR3byB2YXJpYWJsZXMuIEl0IGlzIGJlbGlldmVkIHRoYXQgdGhlIGFuc3dlciB0byBob3cgbmVjZXNzYXJ5IHRoZSA0UOKAmXMgbWFya2V0aW5nIG1ldGhvZCBpcyBvbiBTdGVhbSBjYW4gYmUgbWVhc3VyZWQgYnkgbG9va2luZyBhdCBlc3RpbWF0ZWQgZ2FtZSBvd25lcnNoaXAuIFRoaXMgaXMgdGhlIGNhc2UgYmVjYXVzZSBnYW1lcyBhcmUgc3VwcG9ydGVkIGJ5IHRoZWlyIGNvbW11bml0aWVzIGFuZCBnYW1lcyB3aXRoIHN0cm9uZyBjb21tdW5pdGllcyB0ZW5kIHRvIGJlIGJvdGggcmVjb21tZW5kZWQgYnkgdGhlaXIgcGxheWVycyB0byBvdGhlciBwb3RlbnRpYWwgcGxheWVycyBhbmQgcGxheWVkIG9uIHN0cmVhbWluZyBzaXRlcyB3aGljaCBidWlsZCBpbnRlcmVzdCBpbiB0aGUgZ2FtZSBhbmQgYnVpbGQgYSBzdHJvbmcgY29tbXVuaXR5Lg0KDQpUaHJvdWdoIHRoZSBhbmFseXNpcyBwcm9jZXNzIGl0IGlzIGltcG9ydGFudCB0byBrZWVwIGluIG1pbmQgdGhhdCBkaWZmZXJlbnQgZ2VucmVzIGNhdGVyIHRvIGRpZmZlcmVudCBpbnRlcmVzdHMgdGhhdCBmaWxsIG5pY2hlcywgbWVhbmluZyB0aGVyZSBpcyBubyBwZXJmZWN0IGdhbWUuIEluIGNvbXBsZXRpbmcgdGhlIGFuYWx5c2lzLCB0aGUgZ29hbCBpcyB0byB1bmRlcnN0YW5kIHdoYXQgU3RlYW0gbG9va3MgbGlrZSBmb3IgdGhlIG1ham9yaXR5IG9mIGdhbWVzIG9uIHRoZSBwbGF0Zm9ybSBhbmQgaG93IGV4cGVjdGF0aW9ucyBkaWZmZXIgYmV0d2VlbiBnZW5yZXMgcmVnYXJkaW5nIHByaWNlIGFuZCBvd25lcnNoaXAuIFRvIGZpbmQgb3V0IHdoYXQgbWFrZXMgYSBnYW1lIHN1Y2Nlc3NmdWwgSSBmaXJzdCBuZWVkZWQgdG8gcnVuIGEgY29ycmVsYXRpb24gYW5hbHlzaXMgdG8gY29uZmlybSB0aGF0IGEgc3Ryb25nIGNvbW11bml0eSBpcyB0aGUgZHJpdmluZyBmb3JjZSBiZWhpbmQgYW4gaW5jcmVhc2UgaW4gbW9zdCB2YXJpYWJsZXMsIHRoaXMgaXMgd2hhdCBsZWQgbWUgdG8gc29ydCBieSBPd25lcnNoaXAuIFRoZSBwdXJwb3NlIG9mIGNob29zaW5nIHRoZSBhY3Rpb24gZ2VucmUgdG8gdXNlIGFzIGEgY29tcGFyaXNvbiBpbiBhZGRpdGlvbiB0byB0aGUgdG9wIDI1MCBnYW1lcyB3YXMgdG8gbGVhcm4gYWJvdXQgd2hhdCB0aGUgbWFqb3JpdHkgb2YgY29uc3VtZXJzIG9uIFN0ZWFtIHByZWZlciBhbmQgdXNpbmcgdGhlIHZhcmlhYmxlcyBhcyBhIGJhc2lzIGZvciBjb21wYXJpc29uLiBVc2luZyB0aGlzIG1ldGhvZCwgdGhlIHBsYW4gaXMgdG8gc2VlIGlmIHRoZXJlIGFyZSBkaWZmZXJlbmNlcyBiZXR3ZWVuIGdlbnJlcyBvbiBzdGVhbSwgZm9sbG93aW5nIHRoZSBQcm9kdWN0IHF1YXJ0ZXIgb2YgdGhlIDRQ4oCZcy4NCg0KIyMgT3ZlcmFsbCBGaW5kaW5ncw0KDQpUaGUgc2ltdWxhdGlvbiBnZW5yZSBhcyBhIHdob2xlIGlzIGEgcG9wdWxhciBnZW5yZSB0aGF0IGlzIGZ1bGwgb2YgYXNwZWN0cyB0aGF0IG1ha2UgdGhlIGdlbnJlIGludGVyZXN0aW5nIHRvIGRpZmZlcmVudCB0eXBlcyBvZiBwbGF5ZXJzLiBUaGVzZSBnYW1lcyBvZnRlbiBpbmNsdWRlIGEgaGlnaCBsZXZlbCBvZiBwbGF5ZXIgZnJlZWRvbSBtZWFuaW5nIHN1Y2ggZ2FtZXMgY2FuIGJlIG1vcmUgZXhwZW5zaXZlIHRvIHByb2R1Y2UuIEluIHRoaXMgY2FzZSwgYW1vbmcgdGhlIHRvcCAyNTAgc2ltdWxhdGlvbiBnYW1lcywgdGhlIG1ham9yaXR5IG9mIHRob3NlIGdhbWVzIGhhdmUgYW4gYXZlcmFnZSBwcmljZSBvZiBcJDE0Ljk5IHdpdGggYXJvdW5kIG9ubHkgMjAlIG9mIHRoZSBnYW1lcyBiZWluZyBmcmVlIHRvIHBsYXkuIFdpdGggdGhpcyBpbiBtaW5kLCBzaW11bGF0aW9uIGdhbWVzIHRlbmQgdG8gYmUgY29tcGxleCBhbmQgaGF2ZSBsb25nIGRldmVsb3BtZW50IHRpbWVzLCBkcml2aW5nIHByaWNlcyB1cCwgdGhpcyBiZWluZyBzYWlkLCBpdCB3YXMgZm91bmQgdGhhdCBnYW1lcyB0aGF0IGFyZSBpbiB0aGUgdG9wIDI1MCBzdGlsbCBkbyBub3QgcmVhY2ggTmludGVuZG8ncyB0eXBpY2FsIHByaWNlIHdpdGggdGhlIG1vc3QgZXhwZW5zaXZlIGdhbWUgaW4gdGhlIHRvcCAyNTAgYmVpbmcgNjkuOTkgYW5kIHJhbmtpbmcgaGlnaGVyIHRoYW4gb25seSBhcHByb3hpbWF0ZWx5IDYwJSBvZiB0aGUgdG9wIGdhbWVzIGRlc3BpdGUgaXRzIGhpZ2ggcHJpY2UgdGFnLg0KDQpUaGVyZSBpcyBhIHN0cm9uZyBjb3JyZWxhdGlvbiBiZXR3ZWVuIHBsYXllciBlbmdhZ2VtZW50IGFuZCB0aGUgb3duZXJzaGlwIG9mIGEgZ2FtZS4gVW5leHBlY3RlZGx5LCB0aGUgYWN0aW9uIGdlbnJlIGFuZCBzaW11bGF0aW9uIGdhbWVzIHRlbmQgdG8gaGF2ZSBzaW1pbGFyIG93bmVyc2hpcC4gVGhpcyB3YXMgc3VycHJpc2luZyB0byBtZSBiZWNhdXNlIEkgcG9zdHVsYXRlZCB0aGF0IHBsYXllcnMgd291bGQgc3BlbmQgdGltZSBvbiBnYW1lcyB3aXRoIG1vcmUgc3RvcnktYmFzZWQgYXNwZWN0cyBidXQgd2hhdCBJIGZvdW5kIGlzIHRoYXQgcGxheWVycyB3aWxsIHB1dCB0aW1lIGludG8gd2hhdCB0aGV5IGFyZSBpbnRlcmVzdGVkIGluIHdoZXRoZXIgdGhlIGdhbWUgaXMgZnVsbCBvZiBjb21iYXQgb3IgYSBzbG93LXBhY2VkIGZhcm1pbmcgZ2FtZS4gVGhlcmVmb3JlLCBpZiBhIGRldmVsb3BlciB3b3VsZCBsaWtlIHRvIG1ha2UgYSBnYW1lLCBidWlsZGluZyBhIHN0cm9uZyBjb21tdW5pdHkgaXMgdGhlIGtleSB0byBpbmNyZWFzaW5nIG93bmVyc2hpcC4NCg0KIyBDb25jbHVzaW9ucw0KDQpUaGUgU3RlYW0gUGxhdGZvcm0gYXMgYSB3aG9sZSBpcyBmdWxsIG9mIGEgd2lkZSB2YXJpZXR5IG9mIGdhbWVzIHRoYXQgdGVuZCB0byBsZWFuIGNsb3NlciB0byB0aGUgaW5kaWUgZGV2ZWxvcGVyIGFzIHRoZSBwbGF0Zm9ybSBpcyB1c2VkIHRvIHB1Ymxpc2ggZ2FtZXMgcmF0aGVyIHRoYW4gcHJlc2VudCBhIHNlbGVjdGVkIHZhcmlldHkgb2YgZ2FtZXMgbGlrZSB0aGUgTmludGVuZG8gc3RvcmUuIFRoZSBtYWpvcml0eSBvZiBnYW1lcyBvbiB0aGlzIHBsYXRmb3JtIHRlbmQgdG8gc2VlIGFuIGVzdGltYXRlZCAxMDAwIGNvcGllcyBzb2xkLCBob3dldmVyIGEgZmV3IGdhbWVzIHJlYWNoIGVzdGltYXRlZCBvd25lcnMgaW4gdGhlIDEwIG1pbGxpb25zLiBTdGVhbSByZXNwb25kcyBiZXN0IHRvIHRoZSBhY3Rpb24gZ2VucmUgYW5kIHRoZXJlIGFyZSBzaWduaWZpY2FudCBkaWZmZXJlbmNlcyBiZXR3ZWVuIHRoZSBhY3Rpb24gYW5kIHNpbXVsYXRpb24gZ2VucmVzLiBJZiBhIGRldmVsb3BlciB3ZXJlIGxvb2tpbmcgdG8gZGlzdHJpYnV0ZSBhIHNpbXVsYXRpb24gZ2FtZSwgdGhlIGRldmVsb3BlciBjYW4gZXhwZWN0IHRoYXQgYSBzdWNjZXNzZnVsIFNpbSBnYW1lIGJhc2VkIG9uIGdhbWUgb3duZXJzaGlwIHdvdWxkIGJlIGRpZmZlcmVudCBmcm9tIGFuIGFjdGlvbiBnYW1lLg0KDQpSZWdhcmRpbmcgcHJpY2UsIHRoZSBkYXRhIHNob3dzIHRoYXQgdGhlIGF2ZXJhZ2UgcHJpY2UgZm9yIGEgZ2VucmUgZGlmZmVycyB3aXRoIGFjdGlvbiBnYW1lcyB0ZW5kaW5nIHRvIGJlIHByaWNlZCBhcm91bmQgdGhlIFwkMTAgcmFuZ2UgYW5kIHNpbXVsYXRpb24gZ2FtZXMgYmVpbmcgcHJpY2VkIGFyb3VuZCBcJDE0Ljk5LiBUaGlzIG1lYW5zIHRoYXQgYSBnYW1lIGluIHRoZSBzaW11bGF0aW9uIGdlbnJlIGJlaW5nIHByaWNlZCBoaWdoZXIgdGhhbiB0aGUgYXZlcmFnZSBwb3B1bGFyIGdhbWUgcHJpY2UgaXMgd2lsbCBub3QgYmUgb3V0IG9mIHRoZSBvcmRpbmFyeS4gQWRkaXRpb25hbGx5LCBhIGdhbWUgYmVpbmcgZnJlZSB0byBwbGF5IGRvZXMgbm90IGFsd2F5cyBsZWFkIHRvIGhpZ2hlciBvd25lcnNoaXAuIE92ZXJhbGwsIGJhc2VkIG9uIHRoZSBwZXJjZW50YWdlIG9mIHBvc2l0aXZlIHJldmlld3MgZm9yIGdhbWVzIGJlaW5nIHJhdGhlciBjb25zaXN0ZW50IGFjcm9zcyBhbGwgbGV2ZWxzIG9mIG93bmVyc2hpcCwgaXQgcmVhbGx5IGlzIGFib3V0IGJlaW5nIGFibGUgdG8gYnVpbGQgYSBzdHJvbmcgY29tbXVuaXR5IGFuZCB0aG91Z2ggbWFya2V0aW5nIGNhbiBiZSBhIHJlYWxseSBncmVhdCBib29zdCBhIGdhbWUgd2lsbCB0ZW5kIHRvIG1ha2UgaXQgdG8gaXRzIGludGVuZGVkIGF1ZGllbmNlLCBpdCByZWFsbHkganVzdCBkZXBlbmRzIG9uIHdoYXQgbGV2ZWwgb2Ygb3duZXJzaGlwIHRoZSBkZXZlbG9wZXIgaXMgYWltaW5nIGZvciB0aGF0IGNoYW5nZXMgdGhlIGFtb3VudCBvZiBlZmZvcnQgYW5kIHRpbWUgdGhhdCBzaG91bGQgYmUgcHV0IGludG8gbWFya2V0aW5nIGJlY2F1c2UgaXQgaXMgdWx0aW1hdGVseSBhIGdvb2QgZ2FtZSBpcyBub3QgbWVhc3VyZWQgb25seSBieSBpdHMgb3duZXJzaGlwLg0KDQpMaW1pdGF0aW9ucyBvZiB0aGUgZGF0YSBzZXQgd291bGQgYmUgdGhlIGxhY2sgb2YgdG90YWwgZ2FtZSByZXZlbnVlIGFuZCBhIGRlZmluaXRlIG1lYXN1cmUgZm9yIHRoZSBxdWFsaXR5IG9mIGEgZ2FtZS4gQWRkaXRpb25hbGx5LCB3aGljaCBtYXJrZXQgdGhlIGRhdGEgY29tZXMgZnJvbSBpcyBub3Qgc3RhdGVkLiBJZiB0aGlzIHZhcmlhYmxlIHdlcmUgdG8gYmUgYXZhaWxhYmxlLCBpdCB3b3VsZCBiZSBpbnRlcmVzdGluZyB0byBjb21wbGV0ZSBhbiBhbmFseXNpcyBjb21wYXJpbmcgU3RlYW0ncyBzdG9yZXMgZm9yIGVhY2ggY291bnRyeS4gQW4gZXhhbXBsZSBvZiBob3cgdGhpcyBkYXRhIG1heSBiZSB1c2VkIHdvdWxkIGJlIHRvIGNvbXBhcmUgaG93IGdlbnJlcyBwZXJmb3JtIGluIGRpZmZlcmVudCBjb3VudHJpZXMuDQoNCiMgUmVmZXJlbmNlcw0KDQpHb2luZyBJbmRpZSBCaXouICgyMDI0LCBKdWx5IDI3KS4gKlN0ZWFtIG1hcmtldGluZyBleHBlcnQgcmV2ZWFscyBhbGdvcml0aG0gc2VjcmV0cyogW1ZpZGVvXS4gWW91VHViZS4gPGh0dHBzOi8vd3d3LnlvdXR1YmUuY29tL3dhdGNoP3Y9Q2ZTVGhXM0d3dk0+DQoNClN1bW1lci4gKDIwMjUsIE1hcmNoIDE3KS4gKlRoZSBGb3VyIFBTIG9mIE1hcmtldGluZzogRGVmaW5pdGlvbiwgUm9sZSwgYW5kIFF1ZXN0aW9ucyB0byBjb25zaWRlciAtIE1hZ2VwbGF6YSouIFRoZSBNb3N0IEZlYXR1cmUtcmljaCBFeHRlbnNpb24gRGV2ZWxvcGVyIGZvciBNYWdlbnRvIDIgLSBBZG9iZSBDb21tZXJjZS4gPGh0dHBzOi8vd3d3Lm1hZ2VwbGF6YS5jb20vYmxvZy80LXBzLW9mLW1hcmtldGluZy5odG1sPg0KDQpGcm9ua29uR2FtZXMuICoiU3RlYW0gR2FtZXMgRGF0YXNldC4iKiAqS2FnZ2xlKiwgMjQgQXVnLiAyMDIzLCB3d3cua2FnZ2xlLmNvbS9kYXRhc2V0cy9mcm9ua29uZ2FtZXMvc3RlYW0tZ2FtZXMtZGF0YXNldC4NCg0KIlNpbXVsYXRpb24gdmlkZW8gZ2FtZS4iICpXaWtpcGVkaWEqLCAzIE5vdi4gMjAyNCwgZW4ud2lraXBlZGlhLm9yZy93aWtpL1NpbXVsYXRpb25fdmlkZW9fZ2FtZS4NCg0KIlN0YXJmaWVsZCAodmlkZW8gZ2FtZSkuIiAqV2lraXBlZGlhKiwgNiBOb3YuIDIwMjQsIGVuLndpa2lwZWRpYS5vcmcvd2lraS9TdGFyZmllbGRcXyh2aWRlb19nYW1lKS4NCg0KIlN0ZWFtIENoYXJ0czogVG9wIDEwMC4iICpTdGVhbSosIHN0b3JlLnN0ZWFtcG93ZXJlZC5jb20vY2hhcnRzLy4gQWNjZXNzZWQgOSBOb3YuIDIwMjUuDQoNCiJTdG9yZSBIb21lLiIgKlN0ZWFtKiwgc3RvcmUuc3RlYW1wb3dlcmVkLmNvbS9nYW1lcy4gQWNjZXNzZWQgOSBOb3YuIDIwMjUuDQoNCiJUb3AgcXVlc3Rpb25zLiIgKlN0YWNrIE92ZXJmbG93Kiwgc3RhY2tvdmVyZmxvdy5jb20vcXVlc3Rpb25zLiBBY2Nlc3NlZCA5IE5vdi4gMjAyNS4NCg0KIldoeSBBcmUgR2FtZXMgU28gRXhwZW5zaXZlIE5vdz8gRmFjdG9ycyBEcml2aW5nIFVwIEdhbWUgUHJpY2VzLiIgKkRIZ2F0ZSBTbWFydCBCbG9nKiwgc21hcnQuZGhnYXRlLmNvbS93aHktYXJlLWdhbWVzLXNvLWV4cGVuc2l2ZS1ub3ctZmFjdG9ycy1kcml2aW5nLXVwLWdhbWUtcHJpY2VzLy4gQWNjZXNzZWQgOSBOb3YuIDIwMjUuDQo=